mirror of
https://github.com/git/git
synced 2024-11-05 18:59:29 +00:00
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>
This commit is contained in:
parent
44701c67fd
commit
f95ebf7429
2 changed files with 46 additions and 10 deletions
|
@ -206,6 +206,7 @@ static int merge_recursive(const char *base_sha1,
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
const char *argv[6];
|
const char *argv[6];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
sprintf(buffer, "GITHEAD_%s", head_sha1);
|
sprintf(buffer, "GITHEAD_%s", head_sha1);
|
||||||
setenv(buffer, head_name, 1);
|
setenv(buffer, head_name, 1);
|
||||||
|
@ -218,12 +219,13 @@ static int merge_recursive(const char *base_sha1,
|
||||||
* and $prev on top of us (when reverting), or the change between
|
* and $prev on top of us (when reverting), or the change between
|
||||||
* $prev and $commit on top of us (when cherry-picking or replaying).
|
* $prev and $commit on top of us (when cherry-picking or replaying).
|
||||||
*/
|
*/
|
||||||
argv[0] = "merge-recursive";
|
argv[i++] = "merge-recursive";
|
||||||
argv[1] = base_sha1;
|
if (base_sha1)
|
||||||
argv[2] = "--";
|
argv[i++] = base_sha1;
|
||||||
argv[3] = head_sha1;
|
argv[i++] = "--";
|
||||||
argv[4] = next_sha1;
|
argv[i++] = head_sha1;
|
||||||
argv[5] = NULL;
|
argv[i++] = next_sha1;
|
||||||
|
argv[i++] = NULL;
|
||||||
|
|
||||||
return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD);
|
return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD);
|
||||||
}
|
}
|
||||||
|
@ -297,9 +299,12 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||||
discard_cache();
|
discard_cache();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!commit->parents)
|
if (!commit->parents) {
|
||||||
die ("Cannot %s a root commit", me);
|
if (action == REVERT)
|
||||||
if (commit->parents->next) {
|
die ("Cannot revert a root commit");
|
||||||
|
parent = NULL;
|
||||||
|
}
|
||||||
|
else if (commit->parents->next) {
|
||||||
/* Reverting or cherry-picking a merge commit */
|
/* Reverting or cherry-picking a merge commit */
|
||||||
int cnt;
|
int cnt;
|
||||||
struct commit_list *p;
|
struct commit_list *p;
|
||||||
|
@ -368,7 +373,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (merge_recursive(sha1_to_hex(base->object.sha1),
|
if (merge_recursive(base == NULL ?
|
||||||
|
NULL : sha1_to_hex(base->object.sha1),
|
||||||
sha1_to_hex(head), "HEAD",
|
sha1_to_hex(head), "HEAD",
|
||||||
sha1_to_hex(next->object.sha1), oneline) ||
|
sha1_to_hex(next->object.sha1), oneline) ||
|
||||||
write_cache_as_tree(head, 0, NULL)) {
|
write_cache_as_tree(head, 0, NULL)) {
|
||||||
|
|
30
t/t3503-cherry-pick-root.sh
Executable file
30
t/t3503-cherry-pick-root.sh
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='test cherry-picking a root commit'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
|
||||||
|
echo first > file1 &&
|
||||||
|
git add file1 &&
|
||||||
|
test_tick &&
|
||||||
|
git commit -m "first" &&
|
||||||
|
|
||||||
|
git symbolic-ref HEAD refs/heads/second &&
|
||||||
|
rm .git/index file1 &&
|
||||||
|
echo second > file2 &&
|
||||||
|
git add file2 &&
|
||||||
|
test_tick &&
|
||||||
|
git commit -m "second"
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'cherry-pick a root commit' '
|
||||||
|
|
||||||
|
git cherry-pick master &&
|
||||||
|
test first = $(cat file1)
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
Loading…
Reference in a new issue