From 3afbae7433563b7989faef0f44a2b094e8b19d2d Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 9 May 2014 21:45:07 -0500 Subject: [PATCH] merge: add --reverse-parents option It would be useful to make `git update` reverse parents as desired. Signed-off-by: Felipe Contreras --- Documentation/merge-options.txt | 4 ++++ builtin/commit.c | 5 +++++ builtin/merge.c | 11 ++++++++++- commit.c | 12 ++++++++++++ commit.h | 1 + t/t7600-merge.sh | 26 ++++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index f08e9b80c5..d1dbac94c0 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -113,4 +113,8 @@ ifndef::git-pull[] Note that not all merge strategies may support progress reporting. +--reverse-parents:: +--no-reverse-parents:: + Reverse the order of parents in the merge commit. + endif::git-pull[] diff --git a/builtin/commit.c b/builtin/commit.c index 2d50756b7a..62feb249b7 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1682,6 +1682,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct strbuf m = STRBUF_INIT; FILE *fp; int allow_fast_forward = 1; + int reverse_parents = 0; if (!reflog_msg) reflog_msg = "commit (merge)"; @@ -1705,9 +1706,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die_errno(_("could not read MERGE_MODE")); if (strstr(sb.buf, "no-ff")) allow_fast_forward = 0; + if (strstr(sb.buf, "reverse")) + reverse_parents = 1; } if (allow_fast_forward) parents = reduce_heads(parents); + if (reverse_parents) + parents = reverse_heads(parents); } else { if (!reflog_msg) reflog_msg = (whence == FROM_CHERRY_PICK) diff --git a/builtin/merge.c b/builtin/merge.c index 101ffeff4c..7442e3882e 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -67,6 +67,7 @@ static int abort_current_merge; static int show_progress = -1; static int default_to_upstream = 1; static const char *sign_commit; +static int reverse_parents; static struct strategy all_strategy[] = { { "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL }, @@ -225,6 +226,8 @@ static struct option builtin_merge_options[] = { { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")), + OPT_BOOL(0, "reverse-parents", &reverse_parents, + N_("reverse the order of parents")), OPT_END() }; @@ -825,6 +828,8 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads) pptr = commit_list_append(head, pptr); pptr = commit_list_append(remoteheads->item, pptr); prepare_to_commit(remoteheads); + if (reverse_parents) + parents = reverse_heads(parents); if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents, result_commit, NULL, sign_commit)) die(_("failed to write commit object")); @@ -848,6 +853,8 @@ static int finish_automerge(struct commit *head, parents = remoteheads; if (!head_subsumed || fast_forward == FF_NO) commit_list_insert(head, &parents); + if (reverse_parents) + parents = reverse_heads(parents); strbuf_addch(&merge_msg, '\n'); prepare_to_commit(remoteheads); if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents, @@ -984,7 +991,9 @@ static void write_merge_state(struct commit_list *remoteheads) die_errno(_("Could not open '%s' for writing"), filename); strbuf_reset(&buf); if (fast_forward == FF_NO) - strbuf_addf(&buf, "no-ff"); + strbuf_addf(&buf, "no-ff "); + if (reverse_parents) + strbuf_addf(&buf, "reverse "); if (write_in_full(fd, buf.buf, buf.len) != buf.len) die_errno(_("Could not write to '%s'"), filename); close(fd); diff --git a/commit.c b/commit.c index 3f4f371e5e..b8a74e1fe2 100644 --- a/commit.c +++ b/commit.c @@ -1085,6 +1085,18 @@ struct commit_list *reduce_heads(struct commit_list *heads) return result; } +struct commit_list *reverse_heads(struct commit_list *heads) +{ + struct commit_list *p; + struct commit_list *result = NULL; + + for (p = heads; p; p = p->next) + commit_list_insert(p->item, &result); + + free_commit_list(heads); + return result; +} + static const char gpg_sig_header[] = "gpgsig"; static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1; diff --git a/commit.h b/commit.h index 5d58be0017..2911b93aef 100644 --- a/commit.h +++ b/commit.h @@ -306,6 +306,7 @@ static inline int single_parent(struct commit *commit) } struct commit_list *reduce_heads(struct commit_list *heads); +struct commit_list *reverse_heads(struct commit_list *heads); struct commit_extra_header { struct commit_extra_header *next; diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 302e238263..4d1b7efe2f 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -461,6 +461,16 @@ test_expect_success 'merge c0 with c1 (no-ff)' ' test_debug 'git log --graph --decorate --oneline --all' +test_expect_success 'merge c0 with c1 (--reverse)' ' + git reset --hard c0 && + test_tick && + git merge --no-ff --reverse c1 && + verify_merge file result.1 && + verify_parents $c1 $c0 +' + +test_debug 'git log --graph --decorate --oneline --all' + test_expect_success 'merge c0 with c1 (merge.ff=false)' ' git reset --hard c0 && test_config merge.ff "false" && @@ -668,6 +678,22 @@ test_expect_success 'merge --no-ff --edit' ' test_cmp actual expected ' +test_expect_success 'merge --reverse --no-commit && commit' ' + git reset --hard c0 && + git merge --no-ff --reverse --no-commit c1 && + EDITOR=: git commit && + verify_parents $c1 $c0 +' + +test_debug 'git log --graph --decorate --oneline --all' + +test_expect_success 'amending reverse merge commit' ' + EDITOR=: git commit --amend && + verify_parents $c1 $c0 +' + +test_debug 'git log --graph --decorate --oneline --all' + test_expect_success GPG 'merge --ff-only tag' ' git reset --hard c0 && git commit --allow-empty -m "A newer commit" && -- 2.32.0.93.g670b81a890