filter-branch: stash away ref map in a branch

With "--state-branch=<branchname>" option, the mapping from old object names and filtered ones in ./map/ directory is stashed away in the object database, and the one from the previous run is read to populate the ./map/ directory, allowing for incremental updates of large trees. Signed-off-by: Ian Campbell <ijc@hellion.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ian Campbell committed Sep 21, 2017 at 08:49 UTC bd2c79fbfef894d788c256d45cef05d99442407a
2 files changed +55 -2
Documentation/git-filter-branch.txt
+7 -1
@@ -14,7 +14,7 @@ SYNOPSIS
14 [--commit-filter <command>] [--tag-name-filter <command>]
15 [--subdirectory-filter <directory>] [--prune-empty]
16 [--original <namespace>] [-d <directory>] [-f | --force]
17 - [--] [<rev-list options>...]
17 + [--state-branch <branch>] [--] [<rev-list options>...]
18
19 DESCRIPTION
20 -----------
@@ -198,6 +198,12 @@ to other tags will be rewritten to point to the underlying commit.
198 directory or when there are already refs starting with
199 'refs/original/', unless forced.
200
201 +--state-branch <branch>::
202 + This option will cause the mapping from old to new objects to
203 + be loaded from named branch upon startup and saved as a new
204 + commit to that branch upon exit, enabling incremental of large
205 + trees. If '<branch>' does not exist it will be created.
206 +
207 <rev-list options>...::
208 Arguments for 'git rev-list'. All positive refs included by
209 these options are rewritten. You may also specify options
git-filter-branch.sh
+48 -1
@@ -86,7 +86,7 @@ USAGE="[--setup <command>] [--env-filter <command>]
86 [--parent-filter <command>] [--msg-filter <command>]
87 [--commit-filter <command>] [--tag-name-filter <command>]
88 [--subdirectory-filter <directory>] [--original <namespace>]
89 - [-d <directory>] [-f | --force]
89 + [-d <directory>] [-f | --force] [--state-branch <branch>]
90 [--] [<rev-list options>...]"
91
92 OPTIONS_SPEC=
@@ -106,6 +106,7 @@ filter_msg=cat
106 filter_commit=
107 filter_tag_name=
108 filter_subdir=
109 +state_branch=
110 orig_namespace=refs/original/
111 force=
112 prune_empty=
@@ -181,6 +182,9 @@ do
182 --original)
183 orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
184 ;;
185 + --state-branch)
186 + state_branch="$OPTARG"
187 + ;;
188 *)
189 usage
190 ;;
@@ -259,6 +263,26 @@ export GIT_INDEX_FILE
263 # map old->new commit ids for rewriting parents
264 mkdir ../map || die "Could not create map/ directory"
265
266 +if test -n "$state_branch"
267 +then
268 + state_commit=$(git rev-parse --no-flags --revs-only "$state_branch")
269 + if test -n "$state_commit"
270 + then
271 + echo "Populating map from $state_branch ($state_commit)" 1>&2
272 + perl -e'open(MAP, "-|", "git show $ARGV[0]:filter.map") or die;
273 + while (<MAP>) {
274 + m/(.*):(.*)/ or die;
275 + open F, ">../map/$1" or die;
276 + print F "$2" or die;
277 + close(F) or die;
278 + }
279 + close(MAP) or die;' "$state_commit" \
280 + || die "Unable to load state from $state_branch:filter.map"
281 + else
282 + echo "Branch $state_branch does not exist. Will create" 1>&2
283 + fi
284 +fi
285 +
286 # we need "--" only if there are no path arguments in $@
287 nonrevs=$(git rev-parse --no-revs "$@") || exit
288 if test -z "$nonrevs"
@@ -590,6 +614,29 @@ test -z "$ORIG_GIT_COMMITTER_DATE" || {
614 export GIT_COMMITTER_DATE
615 }
616
617 +if test -n "$state_branch"
618 +then
619 + echo "Saving rewrite state to $state_branch" 1>&2
620 + state_blob=$(
621 + perl -e'opendir D, "../map" or die;
622 + open H, "|-", "git hash-object -w --stdin" or die;
623 + foreach (sort readdir(D)) {
624 + next if m/^\.\.?$/;
625 + open F, "<../map/$_" or die;
626 + chomp($f = <F>);
627 + print H "$_:$f\n" or die;
628 + }
629 + close(H) or die;' || die "Unable to save state")
630 + state_tree=$(/bin/echo -e "100644 blob $state_blob\tfilter.map" | git mktree)
631 + if test -n "$state_commit"
632 + then
633 + state_commit=$(/bin/echo "Sync" | git commit-tree "$state_tree" -p "$state_commit")
634 + else
635 + state_commit=$(/bin/echo "Sync" | git commit-tree "$state_tree" )
636 + fi
637 + git update-ref "$state_branch" "$state_commit"
638 +fi
639 +
640 cd "$orig_dir"
641 rm -rf "$tempdir"
642