[PATCH 11/11] Improve merge performance by avoiding in-index merges.
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 <spearce@spearce.org>
---
git-merge.sh | 39 ++++++++++++++++++++++-----------------
1 files changed, 22 insertions(+), 17 deletions(-)
Show changes to git-merge.sh +22 −17
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