From 161807349aa1ee853880a5c6e39c53f55b10077d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 12 May 2011 07:09:46 -0400 Subject: [PATCH 1/3] cherry-pick: handle root commits with external strategies The merge-recursive strategy already handles root commits; it cherry-picks the difference between the empty tree and the root commit's tree. However, for external strategies, we dereference NULL and segfault while building the argument list. Instead, let's handle this by passing the empty tree sha1 to the merge script. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/merge.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/builtin/merge.c b/builtin/merge.c index d54e7ddbb1..8a0f6901f9 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -590,6 +590,14 @@ static void write_tree_trivial(unsigned char *sha1) die(_("git write-tree failed to write a tree")); } +static const char *merge_argument(struct commit *commit) +{ + if (commit) + return sha1_to_hex(commit->object.sha1); + else + return EMPTY_TREE_SHA1_HEX; +} + int try_merge_command(const char *strategy, size_t xopts_nr, const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes) @@ -610,11 +618,11 @@ int try_merge_command(const char *strategy, size_t xopts_nr, args[i++] = s; } for (j = common; j; j = j->next) - args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); + args[i++] = xstrdup(merge_argument(j->item)); args[i++] = "--"; args[i++] = head_arg; for (j = remotes; j; j = j->next) - args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); + args[i++] = xstrdup(merge_argument(j->item)); args[i] = NULL; ret = run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&buf); From fad2652673247203014e2c57622a5ffe0eb5ad93 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 12 May 2011 07:09:55 -0400 Subject: [PATCH 2/3] revert: allow reverting a root commit Although it is probably an uncommon operation, there is no reason to disallow it, as it works just fine. It is the reverse of a cherry-pick of a root commit, which is already allowed. We do have to tweak one check on whether we have a merge commit, which assumed we had at least one parent. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/revert.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/builtin/revert.c b/builtin/revert.c index f697e66953..1f27c63343 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -408,8 +408,6 @@ static int do_pick_commit(void) discard_cache(); if (!commit->parents) { - if (action == REVERT) - die (_("Cannot revert a root commit")); parent = NULL; } else if (commit->parents->next) { @@ -467,7 +465,7 @@ static int do_pick_commit(void) strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit "); strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1)); - if (commit->parents->next) { + if (commit->parents && commit->parents->next) { strbuf_addstr(&msgbuf, ", reversing\nchanges made to "); strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1)); } From e9fe74cba4ed4577dcc02f61094c611a1c216fee Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 12 May 2011 07:10:07 -0400 Subject: [PATCH 3/3] t3503: test cherry picking and reverting root commits We already tested cherry-picking a root commit, but only with the internal merge-recursive strategy. Let's also test the recently-allowed reverting of a root commit, as well as testing with external strategies (which until recently triggered a segfault). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t3503-cherry-pick-root.sh | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/t/t3503-cherry-pick-root.sh b/t/t3503-cherry-pick-root.sh index b0faa29918..9aefe3a1be 100755 --- a/t/t3503-cherry-pick-root.sh +++ b/t/t3503-cherry-pick-root.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='test cherry-picking a root commit' +test_description='test cherry-picking (and reverting) a root commit' . ./test-lib.sh @@ -23,7 +23,30 @@ test_expect_success setup ' test_expect_success 'cherry-pick a root commit' ' git cherry-pick master && - test first = $(cat file1) + echo first >expect && + test_cmp expect file1 + +' + +test_expect_success 'revert a root commit' ' + + git revert master && + test_path_is_missing file1 + +' + +test_expect_success 'cherry-pick a root commit with an external strategy' ' + + git cherry-pick --strategy=resolve master && + echo first >expect && + test_cmp expect file1 + +' + +test_expect_success 'revert a root commit with an external strategy' ' + + git revert --strategy=resolve master && + test_path_is_missing file1 '