Merge branch 'pw/rebase-m-signoff-fix'
"git rebase --signoff" used to forget that it needs to add a sign-off to the resulting commit when told to continue after a conflict stops its operation. * pw/rebase-m-signoff-fix: rebase -m: fix --signoff with conflicts sequencer: store commit message in private context sequencer: move current fixups to private context sequencer: start removing private fields from public API sequencer: always free "struct replay_opts"
This commit is contained in:
246
sequencer.c
246
sequencer.c
@ -207,6 +207,46 @@ static GIT_PATH_FUNC(rebase_path_no_reschedule_failed_exec, "rebase-merge/no-res
|
|||||||
static GIT_PATH_FUNC(rebase_path_drop_redundant_commits, "rebase-merge/drop_redundant_commits")
|
static GIT_PATH_FUNC(rebase_path_drop_redundant_commits, "rebase-merge/drop_redundant_commits")
|
||||||
static GIT_PATH_FUNC(rebase_path_keep_redundant_commits, "rebase-merge/keep_redundant_commits")
|
static GIT_PATH_FUNC(rebase_path_keep_redundant_commits, "rebase-merge/keep_redundant_commits")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A 'struct replay_ctx' represents the private state of the sequencer.
|
||||||
|
*/
|
||||||
|
struct replay_ctx {
|
||||||
|
/*
|
||||||
|
* The commit message that will be used except at the end of a
|
||||||
|
* chain of fixup and squash commands.
|
||||||
|
*/
|
||||||
|
struct strbuf message;
|
||||||
|
/*
|
||||||
|
* The list of completed fixup and squash commands in the
|
||||||
|
* current chain.
|
||||||
|
*/
|
||||||
|
struct strbuf current_fixups;
|
||||||
|
/*
|
||||||
|
* Stores the reflog message that will be used when creating a
|
||||||
|
* commit. Points to a static buffer and should not be free()'d.
|
||||||
|
*/
|
||||||
|
const char *reflog_message;
|
||||||
|
/*
|
||||||
|
* The number of completed fixup and squash commands in the
|
||||||
|
* current chain.
|
||||||
|
*/
|
||||||
|
int current_fixup_count;
|
||||||
|
/*
|
||||||
|
* Whether message contains a commit message.
|
||||||
|
*/
|
||||||
|
unsigned have_message :1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct replay_ctx* replay_ctx_new(void)
|
||||||
|
{
|
||||||
|
struct replay_ctx *ctx = xcalloc(1, sizeof(*ctx));
|
||||||
|
|
||||||
|
strbuf_init(&ctx->current_fixups, 0);
|
||||||
|
strbuf_init(&ctx->message, 0);
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A 'struct update_refs_record' represents a value in the update-refs
|
* A 'struct update_refs_record' represents a value in the update-refs
|
||||||
* list. We use a string_list to map refs to these (before, after) pairs.
|
* list. We use a string_list to map refs to these (before, after) pairs.
|
||||||
@ -366,17 +406,26 @@ static const char *gpg_sign_opt_quoted(struct replay_opts *opts)
|
|||||||
return buf.buf;
|
return buf.buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void replay_ctx_release(struct replay_ctx *ctx)
|
||||||
|
{
|
||||||
|
strbuf_release(&ctx->current_fixups);
|
||||||
|
strbuf_release(&ctx->message);
|
||||||
|
}
|
||||||
|
|
||||||
void replay_opts_release(struct replay_opts *opts)
|
void replay_opts_release(struct replay_opts *opts)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
|
|
||||||
free(opts->gpg_sign);
|
free(opts->gpg_sign);
|
||||||
free(opts->reflog_action);
|
free(opts->reflog_action);
|
||||||
free(opts->default_strategy);
|
free(opts->default_strategy);
|
||||||
free(opts->strategy);
|
free(opts->strategy);
|
||||||
strvec_clear (&opts->xopts);
|
strvec_clear (&opts->xopts);
|
||||||
strbuf_release(&opts->current_fixups);
|
|
||||||
if (opts->revs)
|
if (opts->revs)
|
||||||
release_revisions(opts->revs);
|
release_revisions(opts->revs);
|
||||||
free(opts->revs);
|
free(opts->revs);
|
||||||
|
replay_ctx_release(ctx);
|
||||||
|
free(opts->ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sequencer_remove_state(struct replay_opts *opts)
|
int sequencer_remove_state(struct replay_opts *opts)
|
||||||
@ -1084,6 +1133,7 @@ static int run_git_commit(const char *defmsg,
|
|||||||
struct replay_opts *opts,
|
struct replay_opts *opts,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||||
|
|
||||||
if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG))
|
if ((flags & CLEANUP_MSG) && (flags & VERBATIM_MSG))
|
||||||
@ -1101,7 +1151,7 @@ static int run_git_commit(const char *defmsg,
|
|||||||
gpg_opt, gpg_opt);
|
gpg_opt, gpg_opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
strvec_pushf(&cmd.env, GIT_REFLOG_ACTION "=%s", opts->reflog_message);
|
strvec_pushf(&cmd.env, GIT_REFLOG_ACTION "=%s", ctx->reflog_message);
|
||||||
|
|
||||||
if (opts->committer_date_is_author_date)
|
if (opts->committer_date_is_author_date)
|
||||||
strvec_pushf(&cmd.env, "GIT_COMMITTER_DATE=%s",
|
strvec_pushf(&cmd.env, "GIT_COMMITTER_DATE=%s",
|
||||||
@ -1487,6 +1537,7 @@ static int try_to_commit(struct repository *r,
|
|||||||
struct replay_opts *opts, unsigned int flags,
|
struct replay_opts *opts, unsigned int flags,
|
||||||
struct object_id *oid)
|
struct object_id *oid)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
struct object_id tree;
|
struct object_id tree;
|
||||||
struct commit *current_head = NULL;
|
struct commit *current_head = NULL;
|
||||||
struct commit_list *parents = NULL;
|
struct commit_list *parents = NULL;
|
||||||
@ -1648,7 +1699,7 @@ static int try_to_commit(struct repository *r,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_head_with_reflog(current_head, oid, opts->reflog_message,
|
if (update_head_with_reflog(current_head, oid, ctx->reflog_message,
|
||||||
msg, &err)) {
|
msg, &err)) {
|
||||||
res = error("%s", err.buf);
|
res = error("%s", err.buf);
|
||||||
goto out;
|
goto out;
|
||||||
@ -1878,10 +1929,10 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Does the current fixup chain contain a squash command? */
|
/* Does the current fixup chain contain a squash command? */
|
||||||
static int seen_squash(struct replay_opts *opts)
|
static int seen_squash(struct replay_ctx *ctx)
|
||||||
{
|
{
|
||||||
return starts_with(opts->current_fixups.buf, "squash") ||
|
return starts_with(ctx->current_fixups.buf, "squash") ||
|
||||||
strstr(opts->current_fixups.buf, "\nsquash");
|
strstr(ctx->current_fixups.buf, "\nsquash");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)
|
static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)
|
||||||
@ -1957,6 +2008,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,
|
|||||||
enum todo_command command, struct replay_opts *opts,
|
enum todo_command command, struct replay_opts *opts,
|
||||||
unsigned flag)
|
unsigned flag)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
const char *fixup_msg;
|
const char *fixup_msg;
|
||||||
size_t commented_len = 0, fixup_off;
|
size_t commented_len = 0, fixup_off;
|
||||||
/*
|
/*
|
||||||
@ -1965,13 +2017,13 @@ static int append_squash_message(struct strbuf *buf, const char *body,
|
|||||||
* squashing commit messages.
|
* squashing commit messages.
|
||||||
*/
|
*/
|
||||||
if (starts_with(body, "amend!") ||
|
if (starts_with(body, "amend!") ||
|
||||||
((command == TODO_SQUASH || seen_squash(opts)) &&
|
((command == TODO_SQUASH || seen_squash(ctx)) &&
|
||||||
(starts_with(body, "squash!") || starts_with(body, "fixup!"))))
|
(starts_with(body, "squash!") || starts_with(body, "fixup!"))))
|
||||||
commented_len = commit_subject_length(body);
|
commented_len = commit_subject_length(body);
|
||||||
|
|
||||||
strbuf_addf(buf, "\n%s ", comment_line_str);
|
strbuf_addf(buf, "\n%s ", comment_line_str);
|
||||||
strbuf_addf(buf, _(nth_commit_msg_fmt),
|
strbuf_addf(buf, _(nth_commit_msg_fmt),
|
||||||
++opts->current_fixup_count + 1);
|
++ctx->current_fixup_count + 1);
|
||||||
strbuf_addstr(buf, "\n\n");
|
strbuf_addstr(buf, "\n\n");
|
||||||
strbuf_add_commented_lines(buf, body, commented_len, comment_line_str);
|
strbuf_add_commented_lines(buf, body, commented_len, comment_line_str);
|
||||||
/* buf->buf may be reallocated so store an offset into the buffer */
|
/* buf->buf may be reallocated so store an offset into the buffer */
|
||||||
@ -1979,7 +2031,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,
|
|||||||
strbuf_addstr(buf, body + commented_len);
|
strbuf_addstr(buf, body + commented_len);
|
||||||
|
|
||||||
/* fixup -C after squash behaves like squash */
|
/* fixup -C after squash behaves like squash */
|
||||||
if (is_fixup_flag(command, flag) && !seen_squash(opts)) {
|
if (is_fixup_flag(command, flag) && !seen_squash(ctx)) {
|
||||||
/*
|
/*
|
||||||
* We're replacing the commit message so we need to
|
* We're replacing the commit message so we need to
|
||||||
* append the Signed-off-by: trailer if the user
|
* append the Signed-off-by: trailer if the user
|
||||||
@ -2013,12 +2065,13 @@ static int update_squash_messages(struct repository *r,
|
|||||||
struct replay_opts *opts,
|
struct replay_opts *opts,
|
||||||
unsigned flag)
|
unsigned flag)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
const char *message, *body;
|
const char *message, *body;
|
||||||
const char *encoding = get_commit_output_encoding();
|
const char *encoding = get_commit_output_encoding();
|
||||||
|
|
||||||
if (opts->current_fixup_count > 0) {
|
if (ctx->current_fixup_count > 0) {
|
||||||
struct strbuf header = STRBUF_INIT;
|
struct strbuf header = STRBUF_INIT;
|
||||||
char *eol;
|
char *eol;
|
||||||
|
|
||||||
@ -2031,10 +2084,10 @@ static int update_squash_messages(struct repository *r,
|
|||||||
|
|
||||||
strbuf_addf(&header, "%s ", comment_line_str);
|
strbuf_addf(&header, "%s ", comment_line_str);
|
||||||
strbuf_addf(&header, _(combined_commit_msg_fmt),
|
strbuf_addf(&header, _(combined_commit_msg_fmt),
|
||||||
opts->current_fixup_count + 2);
|
ctx->current_fixup_count + 2);
|
||||||
strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
|
strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
|
||||||
strbuf_release(&header);
|
strbuf_release(&header);
|
||||||
if (is_fixup_flag(command, flag) && !seen_squash(opts))
|
if (is_fixup_flag(command, flag) && !seen_squash(ctx))
|
||||||
update_squash_message_for_fixup(&buf);
|
update_squash_message_for_fixup(&buf);
|
||||||
} else {
|
} else {
|
||||||
struct object_id head;
|
struct object_id head;
|
||||||
@ -2081,7 +2134,7 @@ static int update_squash_messages(struct repository *r,
|
|||||||
} else if (command == TODO_FIXUP) {
|
} else if (command == TODO_FIXUP) {
|
||||||
strbuf_addf(&buf, "\n%s ", comment_line_str);
|
strbuf_addf(&buf, "\n%s ", comment_line_str);
|
||||||
strbuf_addf(&buf, _(skip_nth_commit_msg_fmt),
|
strbuf_addf(&buf, _(skip_nth_commit_msg_fmt),
|
||||||
++opts->current_fixup_count + 1);
|
++ctx->current_fixup_count + 1);
|
||||||
strbuf_addstr(&buf, "\n\n");
|
strbuf_addstr(&buf, "\n\n");
|
||||||
strbuf_add_commented_lines(&buf, body, strlen(body),
|
strbuf_add_commented_lines(&buf, body, strlen(body),
|
||||||
comment_line_str);
|
comment_line_str);
|
||||||
@ -2095,12 +2148,12 @@ static int update_squash_messages(struct repository *r,
|
|||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
strbuf_addf(&opts->current_fixups, "%s%s %s",
|
strbuf_addf(&ctx->current_fixups, "%s%s %s",
|
||||||
opts->current_fixups.len ? "\n" : "",
|
ctx->current_fixups.len ? "\n" : "",
|
||||||
command_to_string(command),
|
command_to_string(command),
|
||||||
oid_to_hex(&commit->object.oid));
|
oid_to_hex(&commit->object.oid));
|
||||||
res = write_message(opts->current_fixups.buf,
|
res = write_message(ctx->current_fixups.buf,
|
||||||
opts->current_fixups.len,
|
ctx->current_fixups.len,
|
||||||
rebase_path_current_fixups(), 0);
|
rebase_path_current_fixups(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2178,6 +2231,7 @@ static int do_pick_commit(struct repository *r,
|
|||||||
struct replay_opts *opts,
|
struct replay_opts *opts,
|
||||||
int final_fixup, int *check_todo)
|
int final_fixup, int *check_todo)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
unsigned int flags = should_edit(opts) ? EDIT_MSG : 0;
|
unsigned int flags = should_edit(opts) ? EDIT_MSG : 0;
|
||||||
const char *msg_file = should_edit(opts) ? NULL : git_path_merge_msg(r);
|
const char *msg_file = should_edit(opts) ? NULL : git_path_merge_msg(r);
|
||||||
struct object_id head;
|
struct object_id head;
|
||||||
@ -2185,7 +2239,6 @@ static int do_pick_commit(struct repository *r,
|
|||||||
const char *base_label, *next_label;
|
const char *base_label, *next_label;
|
||||||
char *author = NULL;
|
char *author = NULL;
|
||||||
struct commit_message msg = { NULL, NULL, NULL, NULL };
|
struct commit_message msg = { NULL, NULL, NULL, NULL };
|
||||||
struct strbuf msgbuf = STRBUF_INIT;
|
|
||||||
int res, unborn = 0, reword = 0, allow, drop_commit;
|
int res, unborn = 0, reword = 0, allow, drop_commit;
|
||||||
enum todo_command command = item->command;
|
enum todo_command command = item->command;
|
||||||
struct commit *commit = item->commit;
|
struct commit *commit = item->commit;
|
||||||
@ -2284,7 +2337,7 @@ static int do_pick_commit(struct repository *r,
|
|||||||
next = parent;
|
next = parent;
|
||||||
next_label = msg.parent_label;
|
next_label = msg.parent_label;
|
||||||
if (opts->commit_use_reference) {
|
if (opts->commit_use_reference) {
|
||||||
strbuf_addstr(&msgbuf,
|
strbuf_addstr(&ctx->message,
|
||||||
"# *** SAY WHY WE ARE REVERTING ON THE TITLE LINE ***");
|
"# *** SAY WHY WE ARE REVERTING ON THE TITLE LINE ***");
|
||||||
} else if (skip_prefix(msg.subject, "Revert \"", &orig_subject) &&
|
} else if (skip_prefix(msg.subject, "Revert \"", &orig_subject) &&
|
||||||
/*
|
/*
|
||||||
@ -2293,21 +2346,21 @@ static int do_pick_commit(struct repository *r,
|
|||||||
* thus requiring excessive complexity to deal with.
|
* thus requiring excessive complexity to deal with.
|
||||||
*/
|
*/
|
||||||
!starts_with(orig_subject, "Revert \"")) {
|
!starts_with(orig_subject, "Revert \"")) {
|
||||||
strbuf_addstr(&msgbuf, "Reapply \"");
|
strbuf_addstr(&ctx->message, "Reapply \"");
|
||||||
strbuf_addstr(&msgbuf, orig_subject);
|
strbuf_addstr(&ctx->message, orig_subject);
|
||||||
} else {
|
} else {
|
||||||
strbuf_addstr(&msgbuf, "Revert \"");
|
strbuf_addstr(&ctx->message, "Revert \"");
|
||||||
strbuf_addstr(&msgbuf, msg.subject);
|
strbuf_addstr(&ctx->message, msg.subject);
|
||||||
strbuf_addstr(&msgbuf, "\"");
|
strbuf_addstr(&ctx->message, "\"");
|
||||||
}
|
}
|
||||||
strbuf_addstr(&msgbuf, "\n\nThis reverts commit ");
|
strbuf_addstr(&ctx->message, "\n\nThis reverts commit ");
|
||||||
refer_to_commit(opts, &msgbuf, commit);
|
refer_to_commit(opts, &ctx->message, commit);
|
||||||
|
|
||||||
if (commit->parents && commit->parents->next) {
|
if (commit->parents && commit->parents->next) {
|
||||||
strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
|
strbuf_addstr(&ctx->message, ", reversing\nchanges made to ");
|
||||||
refer_to_commit(opts, &msgbuf, parent);
|
refer_to_commit(opts, &ctx->message, parent);
|
||||||
}
|
}
|
||||||
strbuf_addstr(&msgbuf, ".\n");
|
strbuf_addstr(&ctx->message, ".\n");
|
||||||
} else {
|
} else {
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
@ -2316,21 +2369,22 @@ static int do_pick_commit(struct repository *r,
|
|||||||
next = commit;
|
next = commit;
|
||||||
next_label = msg.label;
|
next_label = msg.label;
|
||||||
|
|
||||||
/* Append the commit log message to msgbuf. */
|
/* Append the commit log message to ctx->message. */
|
||||||
if (find_commit_subject(msg.message, &p))
|
if (find_commit_subject(msg.message, &p))
|
||||||
strbuf_addstr(&msgbuf, p);
|
strbuf_addstr(&ctx->message, p);
|
||||||
|
|
||||||
if (opts->record_origin) {
|
if (opts->record_origin) {
|
||||||
strbuf_complete_line(&msgbuf);
|
strbuf_complete_line(&ctx->message);
|
||||||
if (!has_conforming_footer(&msgbuf, NULL, 0))
|
if (!has_conforming_footer(&ctx->message, NULL, 0))
|
||||||
strbuf_addch(&msgbuf, '\n');
|
strbuf_addch(&ctx->message, '\n');
|
||||||
strbuf_addstr(&msgbuf, cherry_picked_prefix);
|
strbuf_addstr(&ctx->message, cherry_picked_prefix);
|
||||||
strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
|
strbuf_addstr(&ctx->message, oid_to_hex(&commit->object.oid));
|
||||||
strbuf_addstr(&msgbuf, ")\n");
|
strbuf_addstr(&ctx->message, ")\n");
|
||||||
}
|
}
|
||||||
if (!is_fixup(command))
|
if (!is_fixup(command))
|
||||||
author = get_author(msg.message);
|
author = get_author(msg.message);
|
||||||
}
|
}
|
||||||
|
ctx->have_message = 1;
|
||||||
|
|
||||||
if (command == TODO_REWORD)
|
if (command == TODO_REWORD)
|
||||||
reword = 1;
|
reword = 1;
|
||||||
@ -2361,7 +2415,7 @@ static int do_pick_commit(struct repository *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (opts->signoff && !is_fixup(command))
|
if (opts->signoff && !is_fixup(command))
|
||||||
append_signoff(&msgbuf, 0, 0);
|
append_signoff(&ctx->message, 0, 0);
|
||||||
|
|
||||||
if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
|
if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
|
||||||
res = -1;
|
res = -1;
|
||||||
@ -2370,17 +2424,17 @@ static int do_pick_commit(struct repository *r,
|
|||||||
!strcmp(opts->strategy, "ort") ||
|
!strcmp(opts->strategy, "ort") ||
|
||||||
command == TODO_REVERT) {
|
command == TODO_REVERT) {
|
||||||
res = do_recursive_merge(r, base, next, base_label, next_label,
|
res = do_recursive_merge(r, base, next, base_label, next_label,
|
||||||
&head, &msgbuf, opts);
|
&head, &ctx->message, opts);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
res |= write_message(msgbuf.buf, msgbuf.len,
|
res |= write_message(ctx->message.buf, ctx->message.len,
|
||||||
git_path_merge_msg(r), 0);
|
git_path_merge_msg(r), 0);
|
||||||
} else {
|
} else {
|
||||||
struct commit_list *common = NULL;
|
struct commit_list *common = NULL;
|
||||||
struct commit_list *remotes = NULL;
|
struct commit_list *remotes = NULL;
|
||||||
|
|
||||||
res = write_message(msgbuf.buf, msgbuf.len,
|
res = write_message(ctx->message.buf, ctx->message.len,
|
||||||
git_path_merge_msg(r), 0);
|
git_path_merge_msg(r), 0);
|
||||||
|
|
||||||
commit_list_insert(base, &common);
|
commit_list_insert(base, &common);
|
||||||
@ -2458,14 +2512,13 @@ fast_forward_edit:
|
|||||||
unlink(rebase_path_fixup_msg());
|
unlink(rebase_path_fixup_msg());
|
||||||
unlink(rebase_path_squash_msg());
|
unlink(rebase_path_squash_msg());
|
||||||
unlink(rebase_path_current_fixups());
|
unlink(rebase_path_current_fixups());
|
||||||
strbuf_reset(&opts->current_fixups);
|
strbuf_reset(&ctx->current_fixups);
|
||||||
opts->current_fixup_count = 0;
|
ctx->current_fixup_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
free_message(commit, &msg);
|
free_message(commit, &msg);
|
||||||
free(author);
|
free(author);
|
||||||
strbuf_release(&msgbuf);
|
|
||||||
update_abort_safety_file();
|
update_abort_safety_file();
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -2846,12 +2899,14 @@ void sequencer_post_commit_cleanup(struct repository *r, int verbose)
|
|||||||
NULL, REF_NO_DEREF);
|
NULL, REF_NO_DEREF);
|
||||||
|
|
||||||
if (!need_cleanup)
|
if (!need_cleanup)
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
if (!have_finished_the_last_pick())
|
if (!have_finished_the_last_pick())
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
sequencer_remove_state(&opts);
|
sequencer_remove_state(&opts);
|
||||||
|
out:
|
||||||
|
replay_opts_release(&opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void todo_list_write_total_nr(struct todo_list *todo_list)
|
static void todo_list_write_total_nr(struct todo_list *todo_list)
|
||||||
@ -3022,6 +3077,8 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
|
|||||||
|
|
||||||
static int read_populate_opts(struct replay_opts *opts)
|
static int read_populate_opts(struct replay_opts *opts)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
|
|
||||||
if (is_rebase_i(opts)) {
|
if (is_rebase_i(opts)) {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -3081,13 +3138,13 @@ static int read_populate_opts(struct replay_opts *opts)
|
|||||||
read_strategy_opts(opts, &buf);
|
read_strategy_opts(opts, &buf);
|
||||||
strbuf_reset(&buf);
|
strbuf_reset(&buf);
|
||||||
|
|
||||||
if (read_oneliner(&opts->current_fixups,
|
if (read_oneliner(&ctx->current_fixups,
|
||||||
rebase_path_current_fixups(),
|
rebase_path_current_fixups(),
|
||||||
READ_ONELINER_SKIP_IF_EMPTY)) {
|
READ_ONELINER_SKIP_IF_EMPTY)) {
|
||||||
const char *p = opts->current_fixups.buf;
|
const char *p = ctx->current_fixups.buf;
|
||||||
opts->current_fixup_count = 1;
|
ctx->current_fixup_count = 1;
|
||||||
while ((p = strchr(p, '\n'))) {
|
while ((p = strchr(p, '\n'))) {
|
||||||
opts->current_fixup_count++;
|
ctx->current_fixup_count++;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3608,13 +3665,24 @@ static int error_with_patch(struct repository *r,
|
|||||||
struct replay_opts *opts,
|
struct replay_opts *opts,
|
||||||
int exit_code, int to_amend)
|
int exit_code, int to_amend)
|
||||||
{
|
{
|
||||||
if (commit) {
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
if (make_patch(r, commit, opts))
|
|
||||||
|
/*
|
||||||
|
* Write the commit message to be used by "git rebase
|
||||||
|
* --continue". If a "fixup" or "squash" command has conflicts
|
||||||
|
* then we will have already written rebase_path_message() in
|
||||||
|
* error_failed_squash(). If an "edit" command was
|
||||||
|
* fast-forwarded then we don't have a message in ctx->message
|
||||||
|
* and rely on make_patch() to write rebase_path_message()
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
|
if (ctx->have_message && !file_exists(rebase_path_message()) &&
|
||||||
|
write_message(ctx->message.buf, ctx->message.len,
|
||||||
|
rebase_path_message(), 0))
|
||||||
|
return error(_("could not write commit message file"));
|
||||||
|
|
||||||
|
if (commit && make_patch(r, commit, opts))
|
||||||
return -1;
|
return -1;
|
||||||
} else if (copy_file(rebase_path_message(),
|
|
||||||
git_path_merge_msg(r), 0666))
|
|
||||||
return error(_("unable to copy '%s' to '%s'"),
|
|
||||||
git_path_merge_msg(r), rebase_path_message());
|
|
||||||
|
|
||||||
if (to_amend) {
|
if (to_amend) {
|
||||||
if (intend_to_amend())
|
if (intend_to_amend())
|
||||||
@ -3936,6 +4004,7 @@ static int do_merge(struct repository *r,
|
|||||||
const char *arg, int arg_len,
|
const char *arg, int arg_len,
|
||||||
int flags, int *check_todo, struct replay_opts *opts)
|
int flags, int *check_todo, struct replay_opts *opts)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
int run_commit_flags = 0;
|
int run_commit_flags = 0;
|
||||||
struct strbuf ref_name = STRBUF_INIT;
|
struct strbuf ref_name = STRBUF_INIT;
|
||||||
struct commit *head_commit, *merge_commit, *i;
|
struct commit *head_commit, *merge_commit, *i;
|
||||||
@ -4064,40 +4133,31 @@ static int do_merge(struct repository *r,
|
|||||||
write_author_script(message);
|
write_author_script(message);
|
||||||
find_commit_subject(message, &body);
|
find_commit_subject(message, &body);
|
||||||
len = strlen(body);
|
len = strlen(body);
|
||||||
ret = write_message(body, len, git_path_merge_msg(r), 0);
|
strbuf_add(&ctx->message, body, len);
|
||||||
repo_unuse_commit_buffer(r, commit, message);
|
repo_unuse_commit_buffer(r, commit, message);
|
||||||
if (ret) {
|
|
||||||
error_errno(_("could not write '%s'"),
|
|
||||||
git_path_merge_msg(r));
|
|
||||||
goto leave_merge;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
int len;
|
|
||||||
|
|
||||||
strbuf_addf(&buf, "author %s", git_author_info(0));
|
strbuf_addf(&buf, "author %s", git_author_info(0));
|
||||||
write_author_script(buf.buf);
|
write_author_script(buf.buf);
|
||||||
strbuf_reset(&buf);
|
strbuf_release(&buf);
|
||||||
|
|
||||||
if (oneline_offset < arg_len) {
|
if (oneline_offset < arg_len) {
|
||||||
p = arg + oneline_offset;
|
strbuf_add(&ctx->message, arg + oneline_offset,
|
||||||
len = arg_len - oneline_offset;
|
arg_len - oneline_offset);
|
||||||
} else {
|
} else {
|
||||||
strbuf_addf(&buf, "Merge %s '%.*s'",
|
strbuf_addf(&ctx->message, "Merge %s '%.*s'",
|
||||||
to_merge->next ? "branches" : "branch",
|
to_merge->next ? "branches" : "branch",
|
||||||
merge_arg_len, arg);
|
merge_arg_len, arg);
|
||||||
p = buf.buf;
|
|
||||||
len = buf.len;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ret = write_message(p, len, git_path_merge_msg(r), 0);
|
ctx->have_message = 1;
|
||||||
strbuf_release(&buf);
|
if (write_message(ctx->message.buf, ctx->message.len,
|
||||||
if (ret) {
|
git_path_merge_msg(r), 0)) {
|
||||||
error_errno(_("could not write '%s'"),
|
ret = error_errno(_("could not write '%s'"),
|
||||||
git_path_merge_msg(r));
|
git_path_merge_msg(r));
|
||||||
goto leave_merge;
|
goto leave_merge;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (strategy || to_merge->next) {
|
if (strategy || to_merge->next) {
|
||||||
/* Octopus merge */
|
/* Octopus merge */
|
||||||
@ -4758,11 +4818,12 @@ static int pick_one_commit(struct repository *r,
|
|||||||
struct replay_opts *opts,
|
struct replay_opts *opts,
|
||||||
int *check_todo, int* reschedule)
|
int *check_todo, int* reschedule)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
int res;
|
int res;
|
||||||
struct todo_item *item = todo_list->items + todo_list->current;
|
struct todo_item *item = todo_list->items + todo_list->current;
|
||||||
const char *arg = todo_item_get_arg(todo_list, item);
|
const char *arg = todo_item_get_arg(todo_list, item);
|
||||||
if (is_rebase_i(opts))
|
if (is_rebase_i(opts))
|
||||||
opts->reflog_message = reflog_message(
|
ctx->reflog_message = reflog_message(
|
||||||
opts, command_to_string(item->command), NULL);
|
opts, command_to_string(item->command), NULL);
|
||||||
|
|
||||||
res = do_pick_commit(r, item, opts, is_final_fixup(todo_list),
|
res = do_pick_commit(r, item, opts, is_final_fixup(todo_list),
|
||||||
@ -4819,9 +4880,10 @@ static int pick_commits(struct repository *r,
|
|||||||
struct todo_list *todo_list,
|
struct todo_list *todo_list,
|
||||||
struct replay_opts *opts)
|
struct replay_opts *opts)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
int res = 0, reschedule = 0;
|
int res = 0, reschedule = 0;
|
||||||
|
|
||||||
opts->reflog_message = sequencer_reflog_action(opts);
|
ctx->reflog_message = sequencer_reflog_action(opts);
|
||||||
if (opts->allow_ff)
|
if (opts->allow_ff)
|
||||||
assert(!(opts->signoff || opts->no_commit ||
|
assert(!(opts->signoff || opts->no_commit ||
|
||||||
opts->record_origin || should_edit(opts) ||
|
opts->record_origin || should_edit(opts) ||
|
||||||
@ -4871,6 +4933,8 @@ static int pick_commits(struct repository *r,
|
|||||||
return stopped_at_head(r);
|
return stopped_at_head(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
strbuf_reset(&ctx->message);
|
||||||
|
ctx->have_message = 0;
|
||||||
if (item->command <= TODO_SQUASH) {
|
if (item->command <= TODO_SQUASH) {
|
||||||
res = pick_one_commit(r, todo_list, opts, &check_todo,
|
res = pick_one_commit(r, todo_list, opts, &check_todo,
|
||||||
&reschedule);
|
&reschedule);
|
||||||
@ -5076,6 +5140,7 @@ static int commit_staged_changes(struct repository *r,
|
|||||||
struct replay_opts *opts,
|
struct replay_opts *opts,
|
||||||
struct todo_list *todo_list)
|
struct todo_list *todo_list)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
|
unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
|
||||||
unsigned int final_fixup = 0, is_clean;
|
unsigned int final_fixup = 0, is_clean;
|
||||||
|
|
||||||
@ -5112,7 +5177,7 @@ static int commit_staged_changes(struct repository *r,
|
|||||||
* the commit message and if there was a squash, let the user
|
* the commit message and if there was a squash, let the user
|
||||||
* edit it.
|
* edit it.
|
||||||
*/
|
*/
|
||||||
if (!is_clean || !opts->current_fixup_count)
|
if (!is_clean || !ctx->current_fixup_count)
|
||||||
; /* this is not the final fixup */
|
; /* this is not the final fixup */
|
||||||
else if (!oideq(&head, &to_amend) ||
|
else if (!oideq(&head, &to_amend) ||
|
||||||
!file_exists(rebase_path_stopped_sha())) {
|
!file_exists(rebase_path_stopped_sha())) {
|
||||||
@ -5121,20 +5186,20 @@ static int commit_staged_changes(struct repository *r,
|
|||||||
unlink(rebase_path_fixup_msg());
|
unlink(rebase_path_fixup_msg());
|
||||||
unlink(rebase_path_squash_msg());
|
unlink(rebase_path_squash_msg());
|
||||||
unlink(rebase_path_current_fixups());
|
unlink(rebase_path_current_fixups());
|
||||||
strbuf_reset(&opts->current_fixups);
|
strbuf_reset(&ctx->current_fixups);
|
||||||
opts->current_fixup_count = 0;
|
ctx->current_fixup_count = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* we are in a fixup/squash chain */
|
/* we are in a fixup/squash chain */
|
||||||
const char *p = opts->current_fixups.buf;
|
const char *p = ctx->current_fixups.buf;
|
||||||
int len = opts->current_fixups.len;
|
int len = ctx->current_fixups.len;
|
||||||
|
|
||||||
opts->current_fixup_count--;
|
ctx->current_fixup_count--;
|
||||||
if (!len)
|
if (!len)
|
||||||
BUG("Incorrect current_fixups:\n%s", p);
|
BUG("Incorrect current_fixups:\n%s", p);
|
||||||
while (len && p[len - 1] != '\n')
|
while (len && p[len - 1] != '\n')
|
||||||
len--;
|
len--;
|
||||||
strbuf_setlen(&opts->current_fixups, len);
|
strbuf_setlen(&ctx->current_fixups, len);
|
||||||
if (write_message(p, len, rebase_path_current_fixups(),
|
if (write_message(p, len, rebase_path_current_fixups(),
|
||||||
0) < 0)
|
0) < 0)
|
||||||
return error(_("could not write file: '%s'"),
|
return error(_("could not write file: '%s'"),
|
||||||
@ -5151,7 +5216,7 @@ static int commit_staged_changes(struct repository *r,
|
|||||||
* actually need to re-commit with a cleaned up commit
|
* actually need to re-commit with a cleaned up commit
|
||||||
* message.
|
* message.
|
||||||
*/
|
*/
|
||||||
if (opts->current_fixup_count > 0 &&
|
if (ctx->current_fixup_count > 0 &&
|
||||||
!is_fixup(peek_command(todo_list, 0))) {
|
!is_fixup(peek_command(todo_list, 0))) {
|
||||||
final_fixup = 1;
|
final_fixup = 1;
|
||||||
/*
|
/*
|
||||||
@ -5224,20 +5289,21 @@ static int commit_staged_changes(struct repository *r,
|
|||||||
unlink(rebase_path_fixup_msg());
|
unlink(rebase_path_fixup_msg());
|
||||||
unlink(rebase_path_squash_msg());
|
unlink(rebase_path_squash_msg());
|
||||||
}
|
}
|
||||||
if (opts->current_fixup_count > 0) {
|
if (ctx->current_fixup_count > 0) {
|
||||||
/*
|
/*
|
||||||
* Whether final fixup or not, we just cleaned up the commit
|
* Whether final fixup or not, we just cleaned up the commit
|
||||||
* message...
|
* message...
|
||||||
*/
|
*/
|
||||||
unlink(rebase_path_current_fixups());
|
unlink(rebase_path_current_fixups());
|
||||||
strbuf_reset(&opts->current_fixups);
|
strbuf_reset(&ctx->current_fixups);
|
||||||
opts->current_fixup_count = 0;
|
ctx->current_fixup_count = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sequencer_continue(struct repository *r, struct replay_opts *opts)
|
int sequencer_continue(struct repository *r, struct replay_opts *opts)
|
||||||
{
|
{
|
||||||
|
struct replay_ctx *ctx = opts->ctx;
|
||||||
struct todo_list todo_list = TODO_LIST_INIT;
|
struct todo_list todo_list = TODO_LIST_INIT;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
@ -5257,7 +5323,7 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
|
|||||||
unlink(rebase_path_dropped());
|
unlink(rebase_path_dropped());
|
||||||
}
|
}
|
||||||
|
|
||||||
opts->reflog_message = reflog_message(opts, "continue", NULL);
|
ctx->reflog_message = reflog_message(opts, "continue", NULL);
|
||||||
if (commit_staged_changes(r, opts, &todo_list)) {
|
if (commit_staged_changes(r, opts, &todo_list)) {
|
||||||
res = -1;
|
res = -1;
|
||||||
goto release_todo_list;
|
goto release_todo_list;
|
||||||
@ -5309,7 +5375,7 @@ static int single_pick(struct repository *r,
|
|||||||
TODO_PICK : TODO_REVERT;
|
TODO_PICK : TODO_REVERT;
|
||||||
item.commit = cmit;
|
item.commit = cmit;
|
||||||
|
|
||||||
opts->reflog_message = sequencer_reflog_action(opts);
|
opts->ctx->reflog_message = sequencer_reflog_action(opts);
|
||||||
return do_pick_commit(r, &item, opts, 0, &check_todo);
|
return do_pick_commit(r, &item, opts, 0, &check_todo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
sequencer.h
11
sequencer.h
@ -31,6 +31,9 @@ enum commit_msg_cleanup_mode {
|
|||||||
COMMIT_MSG_CLEANUP_ALL
|
COMMIT_MSG_CLEANUP_ALL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct replay_ctx;
|
||||||
|
struct replay_ctx* replay_ctx_new(void);
|
||||||
|
|
||||||
struct replay_opts {
|
struct replay_opts {
|
||||||
enum replay_action action;
|
enum replay_action action;
|
||||||
|
|
||||||
@ -68,10 +71,6 @@ struct replay_opts {
|
|||||||
/* Reflog */
|
/* Reflog */
|
||||||
char *reflog_action;
|
char *reflog_action;
|
||||||
|
|
||||||
/* Used by fixup/squash */
|
|
||||||
struct strbuf current_fixups;
|
|
||||||
int current_fixup_count;
|
|
||||||
|
|
||||||
/* placeholder commit for -i --root */
|
/* placeholder commit for -i --root */
|
||||||
struct object_id squash_onto;
|
struct object_id squash_onto;
|
||||||
int have_squash_onto;
|
int have_squash_onto;
|
||||||
@ -80,13 +79,13 @@ struct replay_opts {
|
|||||||
struct rev_info *revs;
|
struct rev_info *revs;
|
||||||
|
|
||||||
/* Private use */
|
/* Private use */
|
||||||
const char *reflog_message;
|
struct replay_ctx *ctx;
|
||||||
};
|
};
|
||||||
#define REPLAY_OPTS_INIT { \
|
#define REPLAY_OPTS_INIT { \
|
||||||
.edit = -1, \
|
.edit = -1, \
|
||||||
.action = -1, \
|
.action = -1, \
|
||||||
.current_fixups = STRBUF_INIT, \
|
|
||||||
.xopts = STRVEC_INIT, \
|
.xopts = STRVEC_INIT, \
|
||||||
|
.ctx = replay_ctx_new(), \
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5,12 +5,17 @@ test_description='git rebase --signoff
|
|||||||
This test runs git rebase --signoff and make sure that it works.
|
This test runs git rebase --signoff and make sure that it works.
|
||||||
'
|
'
|
||||||
|
|
||||||
TEST_PASSES_SANITIZE_LEAK=true
|
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
. "$TEST_DIRECTORY"/lib-rebase.sh
|
||||||
|
|
||||||
test_expect_success 'setup' '
|
test_expect_success 'setup' '
|
||||||
git commit --allow-empty -m "Initial empty commit" &&
|
git commit --allow-empty -m "Initial empty commit" &&
|
||||||
test_commit first file a &&
|
test_commit first file a &&
|
||||||
|
test_commit second file &&
|
||||||
|
git checkout -b conflict-branch first &&
|
||||||
|
test_commit file-2 file-2 &&
|
||||||
|
test_commit conflict file &&
|
||||||
|
test_commit third file &&
|
||||||
|
|
||||||
ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" &&
|
ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" &&
|
||||||
|
|
||||||
@ -28,6 +33,22 @@ test_expect_success 'setup' '
|
|||||||
Signed-off-by: $ident
|
Signed-off-by: $ident
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# Expected commit message after conflict resolution for rebase --signoff
|
||||||
|
cat >expected-signed-conflict <<-EOF &&
|
||||||
|
third
|
||||||
|
|
||||||
|
Signed-off-by: $ident
|
||||||
|
|
||||||
|
conflict
|
||||||
|
|
||||||
|
Signed-off-by: $ident
|
||||||
|
|
||||||
|
file-2
|
||||||
|
|
||||||
|
Signed-off-by: $ident
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
# Expected commit message after rebase without --signoff (or with --no-signoff)
|
# Expected commit message after rebase without --signoff (or with --no-signoff)
|
||||||
cat >expected-unsigned <<-EOF &&
|
cat >expected-unsigned <<-EOF &&
|
||||||
first
|
first
|
||||||
@ -39,8 +60,12 @@ test_expect_success 'setup' '
|
|||||||
# We configure an alias to do the rebase --signoff so that
|
# We configure an alias to do the rebase --signoff so that
|
||||||
# on the next subtest we can show that --no-signoff overrides the alias
|
# on the next subtest we can show that --no-signoff overrides the alias
|
||||||
test_expect_success 'rebase --apply --signoff adds a sign-off line' '
|
test_expect_success 'rebase --apply --signoff adds a sign-off line' '
|
||||||
git rbs --apply HEAD^ &&
|
test_must_fail git rbs --apply second third &&
|
||||||
test_commit_message HEAD expected-signed
|
git checkout --theirs file &&
|
||||||
|
git add file &&
|
||||||
|
git rebase --continue &&
|
||||||
|
git log --format=%B -n3 >actual &&
|
||||||
|
test_cmp expected-signed-conflict actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'rebase --no-signoff does not add a sign-off line' '
|
test_expect_success 'rebase --no-signoff does not add a sign-off line' '
|
||||||
@ -51,28 +76,65 @@ test_expect_success 'rebase --no-signoff does not add a sign-off line' '
|
|||||||
|
|
||||||
test_expect_success 'rebase --exec --signoff adds a sign-off line' '
|
test_expect_success 'rebase --exec --signoff adds a sign-off line' '
|
||||||
test_when_finished "rm exec" &&
|
test_when_finished "rm exec" &&
|
||||||
git commit --amend -m "first" &&
|
git rebase --exec "touch exec" --signoff first^ first &&
|
||||||
git rebase --exec "touch exec" --signoff HEAD^ &&
|
|
||||||
test_path_is_file exec &&
|
test_path_is_file exec &&
|
||||||
test_commit_message HEAD expected-signed
|
test_commit_message HEAD expected-signed
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'rebase --root --signoff adds a sign-off line' '
|
test_expect_success 'rebase --root --signoff adds a sign-off line' '
|
||||||
git commit --amend -m "first" &&
|
git checkout first &&
|
||||||
git rebase --root --keep-empty --signoff &&
|
git rebase --root --keep-empty --signoff &&
|
||||||
test_commit_message HEAD^ expected-initial-signed &&
|
test_commit_message HEAD^ expected-initial-signed &&
|
||||||
test_commit_message HEAD expected-signed
|
test_commit_message HEAD expected-signed
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'rebase -i --signoff fails' '
|
test_expect_success 'rebase -m --signoff adds a sign-off line' '
|
||||||
git commit --amend -m "first" &&
|
test_must_fail git rebase -m --signoff second third &&
|
||||||
git rebase -i --signoff HEAD^ &&
|
git checkout --theirs file &&
|
||||||
test_commit_message HEAD expected-signed
|
git add file &&
|
||||||
|
GIT_EDITOR="sed -n /Conflicts:/,/^\\\$/p >actual" \
|
||||||
|
git rebase --continue &&
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
# Conflicts:
|
||||||
|
# file
|
||||||
|
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual &&
|
||||||
|
git log --format=%B -n3 >actual &&
|
||||||
|
test_cmp expected-signed-conflict actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'rebase -m --signoff fails' '
|
test_expect_success 'rebase -i --signoff adds a sign-off line when editing commit' '
|
||||||
git commit --amend -m "first" &&
|
(
|
||||||
git rebase -m --signoff HEAD^ &&
|
set_fake_editor &&
|
||||||
test_commit_message HEAD expected-signed
|
FAKE_LINES="edit 1 edit 3 edit 2" \
|
||||||
|
git rebase -i --signoff first third
|
||||||
|
) &&
|
||||||
|
echo a >a &&
|
||||||
|
git add a &&
|
||||||
|
test_must_fail git rebase --continue &&
|
||||||
|
git checkout --ours file &&
|
||||||
|
echo b >a &&
|
||||||
|
git add a file &&
|
||||||
|
git rebase --continue &&
|
||||||
|
echo c >a &&
|
||||||
|
git add a &&
|
||||||
|
git log --format=%B -n3 >actual &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
conflict
|
||||||
|
|
||||||
|
Signed-off-by: $ident
|
||||||
|
|
||||||
|
third
|
||||||
|
|
||||||
|
Signed-off-by: $ident
|
||||||
|
|
||||||
|
file-2
|
||||||
|
|
||||||
|
Signed-off-by: $ident
|
||||||
|
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
@ -71,7 +71,7 @@ test_rebase_continue_update_encode () {
|
|||||||
git config i18n.commitencoding $new &&
|
git config i18n.commitencoding $new &&
|
||||||
test_must_fail git rebase -m main &&
|
test_must_fail git rebase -m main &&
|
||||||
test -f .git/rebase-merge/message &&
|
test -f .git/rebase-merge/message &&
|
||||||
git stripspace <.git/rebase-merge/message >two.t &&
|
git stripspace -s <.git/rebase-merge/message >two.t &&
|
||||||
git add two.t &&
|
git add two.t &&
|
||||||
git rebase --continue &&
|
git rebase --continue &&
|
||||||
compare_msg $msgfile $old $new &&
|
compare_msg $msgfile $old $new &&
|
||||||
|
Reference in New Issue
Block a user