Commit 9585e406 authored by Junio C Hamano's avatar Junio C Hamano

Try to find the optimum merge base while resolving.

The merge-base command acquires a new option, '--all', that causes it
to output all the common ancestor candidates.  The "git resolve"
command then uses it to pick the optimum merge base by picking the one
that results in the smallest number of nontrivial merges.
Signed-off-by: default avatarJunio C Hamano <junkio@cox.net>
parent 2a29da7c
......@@ -49,7 +49,41 @@ if [ "$common" == "$head" ]; then
dropheads
exit 0
fi
echo "Trying to merge $merge into $head"
# Find an optimum merge base if there are more than one candidates.
LF='
'
common=$(git-merge-base -a $head $merge)
case "$common" in
?*"$LF"?*)
echo "Trying to find the optimum merge base."
G=.tmp-index$$
best=
best_cnt=-1
for c in $common
do
rm -f $G
GIT_INDEX_FILE=$G git-read-tree -m $c $head $merge \
2>/dev/null || continue
# Count the paths that are unmerged.
cnt=`GIT_INDEX_FILE=$G git-ls-files --unmerged | wc -l`
if test $best_cnt -le 0 -o $cnt -le $best_cnt
then
best=$c
best_cnt=$cnt
if test "$best_cnt" -eq 0
then
# Cannot do any better than all trivial merge.
break
fi
fi
done
rm -f $G
common="$best"
esac
echo "Trying to merge $merge into $head using $common."
git-update-cache --refresh 2>/dev/null
git-read-tree -u -m $common $head $merge || exit 1
result_tree=$(git-write-tree 2> /dev/null)
if [ $? -ne 0 ]; then
......
......@@ -82,13 +82,17 @@ static struct commit *interesting(struct commit_list *list)
* commit B.
*/
static struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
static int show_all = 0;
static int merge_base(struct commit *rev1, struct commit *rev2)
{
struct commit_list *list = NULL;
struct commit_list *result = NULL;
if (rev1 == rev2)
return rev1;
if (rev1 == rev2) {
printf("%s\n", sha1_to_hex(rev1->object.sha1));
return 0;
}
parse_commit(rev1);
parse_commit(rev2);
......@@ -108,7 +112,7 @@ static struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
if (flags == 3) {
insert_by_date(commit, &result);
/* Mark children of a found merge uninteresting */
/* Mark parents of a found merge uninteresting */
flags |= UNINTERESTING;
}
parents = commit->parents;
......@@ -122,26 +126,46 @@ static struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
insert_by_date(p, &list);
}
}
return interesting(result);
if (!result)
return 1;
while (result) {
struct commit *commit = result->item;
result = result->next;
if (commit->object.flags & UNINTERESTING)
continue;
printf("%s\n", sha1_to_hex(commit->object.sha1));
if (!show_all)
return 0;
commit->object.flags |= UNINTERESTING;
}
return 0;
}
static const char merge_base_usage[] =
"git-merge-base [--all] <commit-id> <commit-id>";
int main(int argc, char **argv)
{
struct commit *rev1, *rev2, *ret;
struct commit *rev1, *rev2;
unsigned char rev1key[20], rev2key[20];
while (1 < argc && argv[1][0] == '-') {
char *arg = argv[1];
if (!strcmp(arg, "-a") || !strcmp(arg, "--all"))
show_all = 1;
else
usage(merge_base_usage);
argc--; argv++;
}
if (argc != 3 ||
get_sha1(argv[1], rev1key) ||
get_sha1(argv[2], rev2key)) {
usage("git-merge-base <commit-id> <commit-id>");
}
get_sha1(argv[2], rev2key))
usage(merge_base_usage);
rev1 = lookup_commit_reference(rev1key);
rev2 = lookup_commit_reference(rev2key);
if (!rev1 || !rev2)
return 1;
ret = common_ancestor(rev1, rev2);
if (!ret)
return 1;
printf("%s\n", sha1_to_hex(ret->object.sha1));
return 0;
return merge_base(rev1, rev2);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment