@matheusbsbs / matheus-bagliano / commits / f95ebf7429
Fork 0

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>

Johannes Schindelin committed Jul 4, 2008 at 16:19 UTC f95ebf74296077d5fdccaa2668edc527841db521
2 files changed +46 -10
builtin-revert.c
+16 -10
@@ -206,6 +206,7 @@ static int merge_recursive(const char *base_sha1,
206 {
207 char buffer[256];
208 const char *argv[6];
209 + int i = 0;
210
211 sprintf(buffer, "GITHEAD_%s", head_sha1);
212 setenv(buffer, head_name, 1);
@@ -218,12 +219,13 @@ static int merge_recursive(const char *base_sha1,
219 * and $prev on top of us (when reverting), or the change between
220 * $prev and $commit on top of us (when cherry-picking or replaying).
221 */
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;
229
230 return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD);
231 }
@@ -297,9 +299,12 @@ static int revert_or_cherry_pick(int argc, const char **argv)
299 discard_cache();
300 }
301
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) {
308 /* Reverting or cherry-picking a merge commit */
309 int cnt;
310 struct commit_list *p;
@@ -368,7 +373,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
373 }
374 }
375
371 - if (merge_recursive(sha1_to_hex(base->object.sha1),
376 + if (merge_recursive(base == NULL ?
377 + NULL : sha1_to_hex(base->object.sha1),
378 sha1_to_hex(head), "HEAD",
379 sha1_to_hex(next->object.sha1), oneline) ||
380 write_cache_as_tree(head, 0, NULL)) {
t/t3503-cherry-pick-root.sh new
+30
@@ -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