Junio C Hamano <junkio@cox.net> writes: > Probably the ideal way would be to give merge-base an option to > spit out all the candidates, and have the script try to see > which ones yield the least number of non-trivial merges. I first checked out your 702c7e.. commit, and slurped Linus tip (back then, 81065e2f415af6c028eac13f481fb9e60a0b487b). Then I ran git resolve with the attached patch (against the tip of git.git "master" branch). Here is what happened, which seems to work a little bit better, at least to me. prompt$ git checkout -f prompt$ git status nothing to commit prompt$ ls -l .git/HEAD lrwxrwxrwx 1 junio src 26 Aug 23 15:43 .git/HEAD -> refs/heads/lenb prompt$ git resolve HEAD origin 'Merge Linus into Lenb' Trying to find the optimum merge base Trying to merge 81065e2f415af6c028eac13f481fb9e60a0b487b into 702c7e7626deeabb057b6f529167b65ec2eefbdb using 3edea4833a1efcd43e1dff082bc8001fdfe74b34 Simple merge failed, trying Automatic merge Auto-merging Documentation/acpi-hotkey.txt. merge: warning: conflicts during merge ERROR: Merge conflict in Documentation/acpi-hotkey.txt. Auto-merging drivers/acpi/osl.c. fatal: merge program failed Automatic merge failed, fix up by hand Only lightly tested, in the sense that I did only this one case and nothing else. For a large repository and with complex merges, "merge-base -a" _might_ end up reporting many candidates, in which case the pre-merge step to figure out the best merge base may turn out to be disastrously slow. I dunno. --- git diff HEAD diff --git a/git-resolve-script b/git-resolve-script --- a/git-resolve-script +++ b/git-resolve-script @@ -49,7 +49,42 @@ if [ "$common" == "$head" ]; then dropheads exit 0 fi -echo "Trying to merge $merge into $head" + +# Find optimum merge base if there are more than one candidate. +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 + if GIT_INDEX_FILE=$G git-write-tree 2>/dev/null + then + # This one results in just a Simple merge; + # It cannot become better than this. + best=$c + break + fi + # Otherwise, 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 + fi + done + rm -f $G + common="$best" +esac + +echo "Trying to merge $merge into $head using $common" 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 --- a/merge-base.c +++ b/merge-base.c @@ -82,13 +82,17 @@ static struct commit *interesting(struct * 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(st 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(st 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); } - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.htmlReceived on Wed Aug 24 11:11:18 2005
This archive was generated by hypermail 2.1.8 : 2005-08-24 11:11:20 EST