Skip to content

Commit f95ebf7

Browse files
dschogitster
authored andcommitted
Allow cherry-picking root commits
A root commit couldn't be cherry-picked. But its semantics can be defined as simply merging two trees by overlaying disjoint parts and merging overlapping files without any common ancestor. You should be able to rebase originally independent branches on top of another branch by using this. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 44701c6 commit f95ebf7

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

builtin-revert.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ static int merge_recursive(const char *base_sha1,
206206
{
207207
char buffer[256];
208208
const char *argv[6];
209+
int i = 0;
209210

210211
sprintf(buffer, "GITHEAD_%s", head_sha1);
211212
setenv(buffer, head_name, 1);
@@ -218,12 +219,13 @@ static int merge_recursive(const char *base_sha1,
218219
* and $prev on top of us (when reverting), or the change between
219220
* $prev and $commit on top of us (when cherry-picking or replaying).
220221
*/
221-
argv[0] = "merge-recursive";
222-
argv[1] = base_sha1;
223-
argv[2] = "--";
224-
argv[3] = head_sha1;
225-
argv[4] = next_sha1;
226-
argv[5] = NULL;
222+
argv[i++] = "merge-recursive";
223+
if (base_sha1)
224+
argv[i++] = base_sha1;
225+
argv[i++] = "--";
226+
argv[i++] = head_sha1;
227+
argv[i++] = next_sha1;
228+
argv[i++] = NULL;
227229

228230
return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD);
229231
}
@@ -297,9 +299,12 @@ static int revert_or_cherry_pick(int argc, const char **argv)
297299
discard_cache();
298300
}
299301

300-
if (!commit->parents)
301-
die ("Cannot %s a root commit", me);
302-
if (commit->parents->next) {
302+
if (!commit->parents) {
303+
if (action == REVERT)
304+
die ("Cannot revert a root commit");
305+
parent = NULL;
306+
}
307+
else if (commit->parents->next) {
303308
/* Reverting or cherry-picking a merge commit */
304309
int cnt;
305310
struct commit_list *p;
@@ -368,7 +373,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
368373
}
369374
}
370375

371-
if (merge_recursive(sha1_to_hex(base->object.sha1),
376+
if (merge_recursive(base == NULL ?
377+
NULL : sha1_to_hex(base->object.sha1),
372378
sha1_to_hex(head), "HEAD",
373379
sha1_to_hex(next->object.sha1), oneline) ||
374380
write_cache_as_tree(head, 0, NULL)) {

t/t3503-cherry-pick-root.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/sh
2+
3+
test_description='test cherry-picking a root commit'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success setup '
8+
9+
echo first > file1 &&
10+
git add file1 &&
11+
test_tick &&
12+
git commit -m "first" &&
13+
14+
git symbolic-ref HEAD refs/heads/second &&
15+
rm .git/index file1 &&
16+
echo second > file2 &&
17+
git add file2 &&
18+
test_tick &&
19+
git commit -m "second"
20+
21+
'
22+
23+
test_expect_success 'cherry-pick a root commit' '
24+
25+
git cherry-pick master &&
26+
test first = $(cat file1)
27+
28+
'
29+
30+
test_done

0 commit comments

Comments
 (0)