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

[PATCH] Fall back to three-way merge when applying a patch.

From
Junio C Hamano <junkio@cox.net>
Date
Oct 5, 2005, 00:46 UTC
Message-ID
<7vd5mk7pv6.fsf@assigned-by-dhcp.cox.net>

After git-apply fails, attempt to find a base tree that the patch cleanly applies to, and do a three-way merge using that base tree into the current index.

When the fall-back merge fails, the working tree can be resolved the same way as you would normally hand resolve a conflicting merge. When making commit, use .dotest/final-commit as the log message template. Or you could just choose to 'git-checkout-index -f -a' to revert the failed merge.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 * I will be placing this in the proposed updates branch.
   Hopefully this would alleviate the complaints from people who
   find the "no fuzz" policy of git-apply is too strict.
   The change is helped if the patch sender uses the updated
   git-format-patch that records which tree the patch is
   supposed to cleanly apply to, but that is not strictly
   necessary; it tries to find a tree that patch applies to from
   the recent commits itself.
 git-applypatch.sh |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 61 insertions(+), 1 deletions(-)

applies-to: 9eec9ff9326032bca405a12a265918725edf4ac7 fb533c6562481dfbc4719f740aa0d85e2a45700c

diff --git a/git-applypatch.sh b/git-applypatch.sh
--- a/git-applypatch.sh
+++ b/git-applypatch.sh
@@ -105,7 +105,67 @@ git-apply --index "$PATCHFILE" || {
 	# Here if we know which revision the patch applies to,
 	# we create a temporary working tree and index, apply the
 	# patch, and attempt 3-way merge with the resulting tree.
-	exit 1
+
+	O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
+	rm -fr .patch-merge-*
+
+	(
+		N=10
+
+		# if the patch records the base tree...
+		sed -ne '
+			/^diff /q
+			/^applies-to: \([0-9a-f]*\)$/{
+				s//\1/p
+				q
+			}
+		' "$PATCHFILE"
+
+		# or hoping the patch is against our recent commits...
+		git-rev-list --max-count=$N HEAD
+
+		# or hoping the patch is against known tags...
+		git-ls-remote --tags .
+	) |
+	while read base junk
+	do
+		# Try it if we have it as a tree.
+		git-cat-file tree "$base" >/dev/null 2>&1 || continue
+
+		rm -fr .patch-merge-tmp-* &&
+		mkdir .patch-merge-tmp-dir || break
+		(
+			cd .patch-merge-tmp-dir &&
+			GIT_INDEX_FILE=../.patch-merge-tmp-index &&
+			GIT_OBJECT_DIRECTORY="$O_OBJECT" &&
+			export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY &&
+			git-read-tree "$base" &&
+			git-apply --index &&
+			mv ../.patch-merge-tmp-index ../.patch-merge-index &&
+			echo "$base" >../.patch-merge-base
+		) <"$PATCHFILE"  2>/dev/null && break
+	done
+
+	test -f .patch-merge-index &&
+	his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&
+	orig_tree=$(cat .patch-merge-base) &&
+	rm -fr .patch-merge-* || exit 1
+
+	echo Falling back to patching base and 3-way merge using $orig_tree...
+
+	# This is not so wrong.  Depending on which base we picked,
+	# orig_tree may be wildly different from ours, but his_tree
+	# has the same set of wildly different changes in parts the
+	# patch did not touch, so resolve ends up cancelling them,
+	# saying that we reverted all those changes.
+
+	if git-merge-resolve $orig_tree -- HEAD $his_tree
+	then
+		echo Done.
+	else
+		echo Failed to merge in the changes.
+		exit 1
+	fi
 }
 
 if test -x "$GIT_DIR"/hooks/pre-applypatch
---
0.99.8.GIT
Next: Linus Torvalds
Message 1 of 17 in “Fall back to three-way merge when applying a patch.”
  1. Fall back to three-way merge when applying a patch.Junio C Hamano, Oct 5, 2005
  2. Linus TorvaldsOct 5, 2005
  3. Junio C HamanoOct 5, 2005
  4. Linus TorvaldsOct 5, 2005
  5. Junio C HamanoOct 6, 2005
  6. Eric W. BiedermanOct 6, 2005
  7. Linus TorvaldsOct 6, 2005
  8. Junio C HamanoOct 6, 2005
  9. Eric W. BiedermanOct 6, 2005
  10. Linus TorvaldsOct 6, 2005
  11. Eric W. BiedermanOct 6, 2005
  12. Linus TorvaldsOct 6, 2005
  13. Eric W. BiedermanOct 6, 2005
  14. Show original and resulting blob object info in diff output.Junio C Hamano, Oct 7, 2005
  15. Linus TorvaldsOct 7, 2005
  16. Junio C HamanoOct 7, 2005
  17. Junio C HamanoOct 6, 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.