зеркало из https://github.com/microsoft/git.git
builtin/merge.c: reduce parents early
Instead of waiting until we record the parents of resulting merge, reduce redundant parents (including our HEAD) immediately after reading them. The change to t7602 illustrates the essence of the effect of this change. The octopus merge strategy used to be fed with redundant commits only to discard them as "up-to-date", but we no longer feed such redundant commits to it and the affected test degenerates to a regular two-head merge. And obviously the known-to-be-broken test in t6028 is now fixed. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
b5d887f906
Коммит
e78cbf8cbb
|
@ -938,31 +938,22 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int finish_automerge(struct commit *head,
|
static int finish_automerge(struct commit *head,
|
||||||
|
int head_subsumed,
|
||||||
struct commit_list *common,
|
struct commit_list *common,
|
||||||
struct commit_list *remoteheads,
|
struct commit_list *remoteheads,
|
||||||
unsigned char *result_tree,
|
unsigned char *result_tree,
|
||||||
const char *wt_strategy)
|
const char *wt_strategy)
|
||||||
{
|
{
|
||||||
struct commit_list *parents = NULL, *j;
|
struct commit_list *parents = NULL;
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
unsigned char result_commit[20];
|
unsigned char result_commit[20];
|
||||||
|
|
||||||
free_commit_list(common);
|
free_commit_list(common);
|
||||||
if (allow_fast_forward) {
|
|
||||||
parents = remoteheads;
|
parents = remoteheads;
|
||||||
|
if (!head_subsumed || !allow_fast_forward)
|
||||||
commit_list_insert(head, &parents);
|
commit_list_insert(head, &parents);
|
||||||
parents = reduce_heads(parents);
|
|
||||||
} else {
|
|
||||||
struct commit_list **pptr = &parents;
|
|
||||||
|
|
||||||
pptr = &commit_list_insert(head,
|
|
||||||
pptr)->next;
|
|
||||||
for (j = remoteheads; j; j = j->next)
|
|
||||||
pptr = &commit_list_insert(j->item, pptr)->next;
|
|
||||||
}
|
|
||||||
strbuf_addch(&merge_msg, '\n');
|
strbuf_addch(&merge_msg, '\n');
|
||||||
prepare_to_commit(remoteheads);
|
prepare_to_commit(remoteheads);
|
||||||
free_commit_list(remoteheads);
|
|
||||||
if (commit_tree(&merge_msg, result_tree, parents, result_commit,
|
if (commit_tree(&merge_msg, result_tree, parents, result_commit,
|
||||||
NULL, sign_commit))
|
NULL, sign_commit))
|
||||||
die(_("failed to write commit object"));
|
die(_("failed to write commit object"));
|
||||||
|
@ -1137,12 +1128,16 @@ static int default_edit_option(void)
|
||||||
st_stdin.st_mode == st_stdout.st_mode);
|
st_stdin.st_mode == st_stdout.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct commit_list *collect_parents(int argc, const char **argv)
|
static struct commit_list *collect_parents(struct commit *head_commit,
|
||||||
|
int *head_subsumed,
|
||||||
|
int argc, const char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct commit_list *remoteheads = NULL;
|
struct commit_list *remoteheads = NULL, *parents, *next;
|
||||||
struct commit_list **remotes = &remoteheads;
|
struct commit_list **remotes = &remoteheads;
|
||||||
|
|
||||||
|
if (head_commit)
|
||||||
|
remotes = &commit_list_insert(head_commit, remotes)->next;
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
struct commit *commit = get_merge_parent(argv[i]);
|
struct commit *commit = get_merge_parent(argv[i]);
|
||||||
if (!commit)
|
if (!commit)
|
||||||
|
@ -1150,6 +1145,20 @@ static struct commit_list *collect_parents(int argc, const char **argv)
|
||||||
remotes = &commit_list_insert(commit, remotes)->next;
|
remotes = &commit_list_insert(commit, remotes)->next;
|
||||||
}
|
}
|
||||||
*remotes = NULL;
|
*remotes = NULL;
|
||||||
|
|
||||||
|
parents = reduce_heads(remoteheads);
|
||||||
|
|
||||||
|
*head_subsumed = 1; /* we will flip this to 0 when we find it */
|
||||||
|
for (remoteheads = NULL, remotes = &remoteheads;
|
||||||
|
parents;
|
||||||
|
parents = next) {
|
||||||
|
struct commit *commit = parents->item;
|
||||||
|
next = parents->next;
|
||||||
|
if (commit == head_commit)
|
||||||
|
*head_subsumed = 0;
|
||||||
|
else
|
||||||
|
remotes = &commit_list_insert(commit, remotes)->next;
|
||||||
|
}
|
||||||
return remoteheads;
|
return remoteheads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1161,7 +1170,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
struct commit *head_commit;
|
struct commit *head_commit;
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
const char *head_arg;
|
const char *head_arg;
|
||||||
int flag, i, ret = 0;
|
int flag, i, ret = 0, head_subsumed;
|
||||||
int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
|
int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
|
||||||
struct commit_list *common = NULL;
|
struct commit_list *common = NULL;
|
||||||
const char *best_strategy = NULL, *wt_strategy = NULL;
|
const char *best_strategy = NULL, *wt_strategy = NULL;
|
||||||
|
@ -1270,7 +1279,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
head_arg = argv[1];
|
head_arg = argv[1];
|
||||||
argv += 2;
|
argv += 2;
|
||||||
argc -= 2;
|
argc -= 2;
|
||||||
remoteheads = collect_parents(argc, argv);
|
remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
|
||||||
} else if (!head_commit) {
|
} else if (!head_commit) {
|
||||||
struct commit *remote_head;
|
struct commit *remote_head;
|
||||||
/*
|
/*
|
||||||
|
@ -1286,7 +1295,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
if (!allow_fast_forward)
|
if (!allow_fast_forward)
|
||||||
die(_("Non-fast-forward commit does not make sense into "
|
die(_("Non-fast-forward commit does not make sense into "
|
||||||
"an empty head"));
|
"an empty head"));
|
||||||
remoteheads = collect_parents(argc, argv);
|
remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
|
||||||
remote_head = remoteheads->item;
|
remote_head = remoteheads->item;
|
||||||
if (!remote_head)
|
if (!remote_head)
|
||||||
die(_("%s - not something we can merge"), argv[0]);
|
die(_("%s - not something we can merge"), argv[0]);
|
||||||
|
@ -1305,7 +1314,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
* the standard merge summary message to be appended
|
* the standard merge summary message to be appended
|
||||||
* to the given message.
|
* to the given message.
|
||||||
*/
|
*/
|
||||||
remoteheads = collect_parents(argc, argv);
|
remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
|
||||||
for (p = remoteheads; p; p = p->next)
|
for (p = remoteheads; p; p = p->next)
|
||||||
merge_name(merge_remote_util(p->item)->name, &merge_names);
|
merge_name(merge_remote_util(p->item)->name, &merge_names);
|
||||||
|
|
||||||
|
@ -1351,7 +1360,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
option_edit = 0;
|
option_edit = 0;
|
||||||
|
|
||||||
if (!use_strategies) {
|
if (!use_strategies) {
|
||||||
if (!remoteheads->next)
|
if (!remoteheads)
|
||||||
|
; /* already up-to-date */
|
||||||
|
else if (!remoteheads->next)
|
||||||
add_strategies(pull_twohead, DEFAULT_TWOHEAD);
|
add_strategies(pull_twohead, DEFAULT_TWOHEAD);
|
||||||
else
|
else
|
||||||
add_strategies(pull_octopus, DEFAULT_OCTOPUS);
|
add_strategies(pull_octopus, DEFAULT_OCTOPUS);
|
||||||
|
@ -1364,7 +1375,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
allow_trivial = 0;
|
allow_trivial = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!remoteheads->next)
|
if (!remoteheads)
|
||||||
|
; /* already up-to-date */
|
||||||
|
else if (!remoteheads->next)
|
||||||
common = get_merge_bases(head_commit, remoteheads->item, 1);
|
common = get_merge_bases(head_commit, remoteheads->item, 1);
|
||||||
else {
|
else {
|
||||||
struct commit_list *list = remoteheads;
|
struct commit_list *list = remoteheads;
|
||||||
|
@ -1376,10 +1389,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.sha1,
|
update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.sha1,
|
||||||
NULL, 0, DIE_ON_ERR);
|
NULL, 0, DIE_ON_ERR);
|
||||||
|
|
||||||
if (!common)
|
if (remoteheads && !common)
|
||||||
; /* No common ancestors found. We need a real merge. */
|
; /* No common ancestors found. We need a real merge. */
|
||||||
else if (!remoteheads->next && !common->next &&
|
else if (!remoteheads ||
|
||||||
common->item == remoteheads->item) {
|
(!remoteheads->next && !common->next &&
|
||||||
|
common->item == remoteheads->item)) {
|
||||||
/*
|
/*
|
||||||
* If head can reach all the merge then we are up to date.
|
* If head can reach all the merge then we are up to date.
|
||||||
* but first the most common case of merging one remote.
|
* but first the most common case of merging one remote.
|
||||||
|
@ -1553,7 +1567,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||||
* auto resolved the merge cleanly.
|
* auto resolved the merge cleanly.
|
||||||
*/
|
*/
|
||||||
if (automerge_was_ok) {
|
if (automerge_was_ok) {
|
||||||
ret = finish_automerge(head_commit, common, remoteheads,
|
ret = finish_automerge(head_commit, head_subsumed,
|
||||||
|
common, remoteheads,
|
||||||
result_tree, wt_strategy);
|
result_tree, wt_strategy);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ test_expect_success 'merge -s subtree up-to-date' '
|
||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_failure 'merge fast-forward octopus' '
|
test_expect_success 'merge fast-forward octopus' '
|
||||||
|
|
||||||
git reset --hard c0 &&
|
git reset --hard c0 &&
|
||||||
test_tick &&
|
test_tick &&
|
||||||
|
|
|
@ -76,7 +76,7 @@ Merge made by the 'recursive' strategy.
|
||||||
create mode 100644 c5.c
|
create mode 100644 c5.c
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
test_expect_failure 'merge reduces irrelevant remote heads' '
|
test_expect_success 'merge reduces irrelevant remote heads' '
|
||||||
GIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual &&
|
GIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual &&
|
||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
|
@ -119,7 +119,7 @@ test_expect_success 'fast-forward to redundant refs' '
|
||||||
git merge c4 c5
|
git merge c4 c5
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_failure 'verify merge result' '
|
test_expect_success 'verify merge result' '
|
||||||
test $(git rev-parse HEAD) = $(git rev-parse c5)
|
test $(git rev-parse HEAD) = $(git rev-parse c5)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче