filter-branch: skip index read/write when possible
If the user specifies an index filter but not a tree filter, filter-branch cleverly avoids checking out the tree entirely. But we don't do the next level of optimization: if you have no index or tree filter, we do not need to read the index at all. This can greatly speed up cases where we are only changing the commit objects (e.g., cementing a graft into place). Here are numbers from the newly-added perf test: Test HEAD^ HEAD --------------------------------------------------------------- 7000.2: noop filter 13.81(4.95+0.83) 5.43(0.42+0.43) -60.7% Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King committed
Nov 6, 2015 at 01:24 UTC
348d4f2fc5d3c4f7ba47079b96676b4e2dd831fc
2 files changed
+40
-2
git-filter-branch.sh
+21
-2
@@ -306,6 +306,15 @@ then
306
start_timestamp=$(date '+%s')
307
fi
308
309
+if test -n "$filter_index" ||
310
+ test -n "$filter_tree" ||
311
+ test -n "$filter_subdir"
312
+then
313
+ need_index=t
314
+else
315
+ need_index=
316
+fi
317
+
318
while read commit parents; do
319
git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1))
320
@@ -313,7 +322,10 @@ while read commit parents; do
322
323
case "$filter_subdir" in
324
"")
316
- GIT_ALLOW_NULL_SHA1=1 git read-tree -i -m $commit
325
+ if test -n "$need_index"
326
+ then
327
+ GIT_ALLOW_NULL_SHA1=1 git read-tree -i -m $commit
328
+ fi
329
;;
330
*)
331
# The commit may not have the subdirectory at all
@@ -387,8 +399,15 @@ while read commit parents; do
399
} <../commit |
400
eval "$filter_msg" > ../message ||
401
die "msg filter failed: $filter_msg"
402
+
403
+ if test -n "$need_index"
404
+ then
405
+ tree=$(git write-tree)
406
+ else
407
+ tree="$commit^{tree}"
408
+ fi
409
workdir=$workdir @SHELL_PATH@ -c "$filter_commit" "git commit-tree" \
391
- $(git write-tree) $parentstr < ../message > ../map/$commit ||
410
+ "$tree" $parentstr < ../message > ../map/$commit ||
411
die "could not write rewritten commit"
412
done <../revs
413
t/perf/p7000-filter-branch.sh
new
+19
@@ -0,0 +1,19 @@
1
+#!/bin/sh
2
+
3
+test_description='performance of filter-branch'
4
+. ./perf-lib.sh
5
+
6
+test_perf_default_repo
7
+test_checkout_worktree
8
+
9
+test_expect_success 'mark bases for tests' '
10
+ git tag -f tip &&
11
+ git tag -f base HEAD~100
12
+'
13
+
14
+test_perf 'noop filter' '
15
+ git checkout --detach tip &&
16
+ git filter-branch -f base..HEAD
17
+'
18
+
19
+test_done