summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2005-08-23 21:08:59 -0700
committerJunio C Hamano <junkio@cox.net>2005-08-23 21:08:59 -0700
commit9585e406224b97b24b46131005b809a6612a3eac (patch)
tree47b47d3fae26e51f2b1d04fd9e898f5a0546da02
parent2a29da7c6d6103c4719c71f6cce88e853260912c (diff)
downloadgit-9585e406224b97b24b46131005b809a6612a3eac.tar.gz
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: Junio C Hamano <junkio@cox.net>
-rwxr-xr-xgit-resolve-script36
-rw-r--r--merge-base.c52
2 files changed, 73 insertions, 15 deletions
diff --git a/git-resolve-script b/git-resolve-script
index 50d5f8336f..7c0e3d8aa8 100755
--- a/git-resolve-script
+++ b/git-resolve-script
@@ -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
diff --git a/merge-base.c b/merge-base.c
index 923256c821..286bf0e8d1 100644
--- a/merge-base.c
+++ b/merge-base.c
@@ -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);
}