git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Automatic merge failed, fix up by hand

From
Junio C Hamano <junkio@cox.net>
Date
Aug 24, 2005, 01:07 UTC
Message-ID
<7v3bp0m9ax.fsf@assigned-by-dhcp.cox.net>
In-Reply-To
<7vek8kmb2a.fsf@assigned-by-dhcp.cox.net>
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);
 }
Previous: Junio C HamanoNext: Linus Torvalds
Message 6 of 12 in “Automatic merge failed, fix up by hand”
  1. Len BrownAug 23, 2005
  2. Junio C HamanoAug 23, 2005
  3. Len BrownAug 23, 2005
  4. Junio C HamanoAug 23, 2005
  5. Junio C HamanoAug 24, 2005
  6. Junio C HamanoAug 24, 2005
  7. Linus TorvaldsAug 24, 2005
  8. Junio C HamanoAug 24, 2005
  9. Len BrownAug 24, 2005
  10. Daniel BarkalowAug 24, 2005
  11. Len BrownAug 24, 2005
  12. Linus TorvaldsAug 24, 2005

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.