Subject: [PATCH 11/11] Improve merge performance by avoiding in-index merges.

From: "Shawn O. Pearce" <[email-masked]>
Date: Thu, 28 Dec 2006 02:35:34 -0500

In the early days of Git we performed a 3-way read-tree based merge
before attempting any specific merge strategy, as our core merge
strategies of merge-one-file and merge-recursive were slower script
based programs which took far longer to execute.  This was a good
performance optimization in the past, as most merges were able to
be handled strictly by `read-tree -m -u`.

However now that merge-recursive is a C based program which performs
a full 3-way read-tree before it starts running we need to pay the
cost of the 3-way read-tree twice if we have to do any sort of file
level merging.  This slows down some classes of simple merges which
`read-tree -m -u` could not handle but which merge-recursive does
automatically.

For a really trivial merge which can be handled entirely by
`read-tree -m -u`, skipping the read-tree and just going directly
into merge-recursive saves on average 50 ms on my PowerPC G4 system.
May sound odd, but it does appear to be true.

In a really simple merge which needs to use merge-recursive to handle
a file that was modified on both branches, skipping the read-tree
in git-merge saves on average almost 100 ms (on the same PowerPC G4)
as we avoid doing some work twice.

We only avoid `read-tree -m -u` if the only strategy to use is
merge-recursive, as not all merge strategies perform as well as
merge-recursive does.

Signed-off-by: Shawn O. Pearce <[email-masked]>
---
 git-merge.sh |   39 ++++++++++++++++++++++-----------------
 1 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/git-merge.sh b/git-merge.sh
index a8f673e..74d4fb0 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -341,23 +341,28 @@ f,*)
 ?,1,*,)
 	# We are not doing octopus, not fast forward, and have only
 	# one common.  See if it is really trivial.
-	git var GIT_COMMITTER_IDENT >/dev/null || exit
-
-	echo "Trying really trivial in-index merge..."
-	git-update-index --refresh 2>/dev/null
-	if git-read-tree --trivial -m -u -v $common $head "$1" &&
-	   result_tree=$(git-write-tree)
-	then
-	    echo "Wonderful."
-	    result_commit=$(
-	        echo "$merge_msg" |
-	        git-commit-tree $result_tree -p HEAD -p "$1"
-	    ) || exit
-	    finish "$result_commit" "In-index merge"
-	    dropsave
-	    exit 0
-	fi
-	echo "Nope."
+	case "$use_strategies" in
+	recursive|'recursive '|recur|'recur ')
+		: run merge later
+		;;
+	*)
+		git var GIT_COMMITTER_IDENT >/dev/null || exit
+		echo "Trying really trivial in-index merge..."
+		git-update-index --refresh 2>/dev/null
+		if git-read-tree --trivial -m -u -v $common $head "$1" &&
+		   result_tree=$(git-write-tree)
+		then
+			echo "Wonderful."
+			result_commit=$(
+				echo "$merge_msg" |
+				git-commit-tree $result_tree -p HEAD -p "$1"
+			) || exit
+			finish "$result_commit" "In-index merge"
+			dropsave
+			exit 0
+		fi
+		echo "Nope."
+	esac
 	;;
 *)
 	# An octopus.  If we can reach all the remote we are up to date.
-- 
1.4.4.3.gd2e4