@@ -1527,6 +1527,9 @@ static int parse_head(struct repository *r, struct commit **head)
return 0;
}
+/* Headers to exclude when copying extra commit headers */
+static const char *exclude_gpgsig[] = { "gpgsig", "gpgsig-sha256", NULL };
+
/*
* Try to commit without forking 'git commit'. In some cases we need
* to run 'git commit' to display an error message
@@ -1538,6 +1541,7 @@ static int parse_head(struct repository *r, struct commit **head)
*/
static int try_to_commit(struct repository *r,
struct strbuf *msg, const char *author,
+ struct commit_extra_header *extra_header,
struct replay_opts *opts, unsigned int flags,
struct object_id *oid)
{
@@ -1545,7 +1549,7 @@ static int try_to_commit(struct repository *r,
struct object_id tree;
struct commit *current_head = NULL;
struct commit_list *parents = NULL;
- struct commit_extra_header *extra = NULL;
+ struct commit_extra_header *extra = extra_header;
struct strbuf err = STRBUF_INIT;
struct strbuf commit_msg = STRBUF_INIT;
char *amend_author = NULL;
@@ -1561,7 +1565,6 @@ static int try_to_commit(struct repository *r,
return -1;
if (flags & AMEND_MSG) {
- const char *exclude_gpgsig[] = { "gpgsig", "gpgsig-sha256", NULL };
const char *out_enc = get_commit_output_encoding();
const char *message = repo_logmsg_reencode(r, current_head,
NULL, out_enc);
@@ -1714,7 +1717,8 @@ static int try_to_commit(struct repository *r,
commit_post_rewrite(r, current_head, oid);
out:
- free_commit_extra_headers(extra);
+ if (extra != extra_header)
+ free_commit_extra_headers(extra);
free_commit_list(parents);
strbuf_release(&err);
strbuf_release(&commit_msg);
@@ -1734,6 +1738,7 @@ static int write_rebase_head(struct object_id *oid)
static int do_commit(struct repository *r,
const char *msg_file, const char *author,
+ struct commit_extra_header *extra_header,
struct replay_opts *opts, unsigned int flags,
struct object_id *oid)
{
@@ -1749,7 +1754,7 @@ static int do_commit(struct repository *r,
msg_file);
res = try_to_commit(r, msg_file ? &sb : NULL,
- author, opts, flags, &oid);
+ author, extra_header, opts, flags, &oid);
strbuf_release(&sb);
if (!res) {
refs_delete_ref(get_main_ref_store(r), "",
@@ -2251,6 +2256,7 @@ static int do_pick_commit(struct repository *r,
int res, unborn = 0, reword = 0, allow, drop_commit;
enum todo_command command = item->command;
struct commit *commit = item->commit;
+ struct commit_extra_header *extra_header = NULL;
if (opts->no_commit) {
/*
@@ -2391,8 +2397,12 @@ static int do_pick_commit(struct repository *r,
strbuf_addstr(&ctx->message, oid_to_hex(&commit->object.oid));
strbuf_addstr(&ctx->message, ")\n");
}
- if (!is_fixup(command))
+ if (!is_fixup(command)) {
author = get_author(msg.message);
+ if (is_rebase_i(opts))
+ extra_header = read_commit_extra_headers(commit,
+ exclude_gpgsig);
+ }
}
ctx->have_message = 1;
@@ -2503,8 +2513,8 @@ static int do_pick_commit(struct repository *r,
} /* else allow == 0 and there's nothing special to do */
if (!opts->no_commit && !drop_commit) {
if (author || command == TODO_REVERT || (flags & AMEND_MSG))
- res = do_commit(r, msg_file, author, opts, flags,
- commit? &commit->object.oid : NULL);
+ res = do_commit(r, msg_file, author, extra_header, opts,
+ flags, commit? &commit->object.oid : NULL);
else
res = error(_("unable to parse commit author"));
*check_todo = !!(flags & EDIT_MSG);
@@ -2535,6 +2545,7 @@ fast_forward_edit:
leave:
free_message(commit, &msg);
free(author);
+ free_commit_extra_headers(extra_header);
update_abort_safety_file();
return res;
@@ -2297,6 +2297,54 @@ test_expect_success 'non-merge commands reject merge commits' '
test_cmp expect actual
'
+test_expect_success 'unconflicted pick copies extra commit headers' '
+ tree="$(git rev-parse C^{tree})" &&
+ parent="$(git rev-parse C^{commit})" &&
+ for i in 1 2 3 4 5 6 7
+ do
+ cat >commit <<-EOF &&
+ tree $tree
+ parent $parent
+ author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ x-extra-header value $i
+
+ An empty commit with an extra header $i
+ EOF
+
+ parent="$(git hash-object -t commit -w commit)" &&
+ eval "oid$i=\$parent" &&
+ test_tick || return 1
+ done &&
+
+ cat >todo <<-EOF &&
+ pick $oid1
+ pick $oid2
+ fixup $oid3
+ reword $oid4
+ edit $oid5
+ pick $oid6
+ squash $oid7
+ EOF
+
+ (
+ set_replace_editor todo &&
+ FAKE_COMMIT_AMEND=EDITED git rebase -i --onto A $oid1^ $oid5
+ ) &&
+ echo changed >file2 &&
+ git add file2 &&
+ FAKE_COMMIT_AMEND=EDITED git rebase --continue &&
+ j=4 &&
+ for i in 1 2 4 5 6
+ do
+ git cat-file commit HEAD~$j >actual &&
+ sed -n -e /^\$/q -e /^x-extra/p actual >actual.extra-header &&
+ echo "x-extra-header value $i" >expect &&
+ test_cmp expect actual.extra-header &&
+ j=$((j-1)) || return 1
+ done
+'
+
# This must be the last test in this file
test_expect_success '$EDITOR and friends are unchanged' '
test_editor_unchanged