Skip to content

Commit 386dd12

Browse files
committed
Merge branch 'ic/fix-filter-branch-to-handle-tag-without-tagger'
"git filter-branch" cannot reproduce a history with a tag without the tagger field, which only ancient versions of Git allowed to be created. This has been corrected. * ic/fix-filter-branch-to-handle-tag-without-tagger: filter-branch: use hash-object instead of mktag filter-branch: stash away ref map in a branch filter-branch: preserve and restore $GIT_AUTHOR_* and $GIT_COMMITTER_* filter-branch: reset $GIT_* before cleaning up
2 parents a515136 + b2c1ca6 commit 386dd12

File tree

2 files changed

+94
-8
lines changed

2 files changed

+94
-8
lines changed

Documentation/git-filter-branch.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ SYNOPSIS
1414
[--commit-filter <command>] [--tag-name-filter <command>]
1515
[--subdirectory-filter <directory>] [--prune-empty]
1616
[--original <namespace>] [-d <directory>] [-f | --force]
17-
[--] [<rev-list options>...]
17+
[--state-branch <branch>] [--] [<rev-list options>...]
1818

1919
DESCRIPTION
2020
-----------
@@ -198,6 +198,12 @@ to other tags will be rewritten to point to the underlying commit.
198198
directory or when there are already refs starting with
199199
'refs/original/', unless forced.
200200

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+
201207
<rev-list options>...::
202208
Arguments for 'git rev-list'. All positive refs included by
203209
these options are rewritten. You may also specify options

git-filter-branch.sh

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ USAGE="[--setup <command>] [--env-filter <command>]
8686
[--parent-filter <command>] [--msg-filter <command>]
8787
[--commit-filter <command>] [--tag-name-filter <command>]
8888
[--subdirectory-filter <directory>] [--original <namespace>]
89-
[-d <directory>] [-f | --force]
89+
[-d <directory>] [-f | --force] [--state-branch <branch>]
9090
[--] [<rev-list options>...]"
9191

9292
OPTIONS_SPEC=
@@ -106,6 +106,7 @@ filter_msg=cat
106106
filter_commit=
107107
filter_tag_name=
108108
filter_subdir=
109+
state_branch=
109110
orig_namespace=refs/original/
110111
force=
111112
prune_empty=
@@ -181,6 +182,9 @@ do
181182
--original)
182183
orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
183184
;;
185+
--state-branch)
186+
state_branch="$OPTARG"
187+
;;
184188
*)
185189
usage
186190
;;
@@ -219,6 +223,13 @@ trap 'cd "$orig_dir"; rm -rf "$tempdir"' 0
219223
ORIG_GIT_DIR="$GIT_DIR"
220224
ORIG_GIT_WORK_TREE="$GIT_WORK_TREE"
221225
ORIG_GIT_INDEX_FILE="$GIT_INDEX_FILE"
226+
ORIG_GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME"
227+
ORIG_GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL"
228+
ORIG_GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE"
229+
ORIG_GIT_COMMITTER_NAME="$GIT_COMMITTER_NAME"
230+
ORIG_GIT_COMMITTER_EMAIL="$GIT_COMMITTER_EMAIL"
231+
ORIG_GIT_COMMITTER_DATE="$GIT_COMMITTER_DATE"
232+
222233
GIT_WORK_TREE=.
223234
export GIT_DIR GIT_WORK_TREE
224235

@@ -252,6 +263,26 @@ export GIT_INDEX_FILE
252263
# map old->new commit ids for rewriting parents
253264
mkdir ../map || die "Could not create map/ directory"
254265

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+
255286
# we need "--" only if there are no path arguments in $@
256287
nonrevs=$(git rev-parse --no-revs "$@") || exit
257288
if test -z "$nonrevs"
@@ -530,7 +561,7 @@ if [ "$filter_tag_name" ]; then
530561
}' \
531562
-e '/^-----BEGIN PGP SIGNATURE-----/q' \
532563
-e 'p' ) |
533-
git mktag) ||
564+
git hash-object -t tag -w --stdin) ||
534565
die "Could not create new tag object for $ref"
535566
if git cat-file tag "$ref" | \
536567
sane_grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1
@@ -544,12 +575,9 @@ if [ "$filter_tag_name" ]; then
544575
done
545576
fi
546577

547-
cd "$orig_dir"
548-
rm -rf "$tempdir"
549-
550-
trap - 0
551-
552578
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
579+
unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
580+
unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE
553581
test -z "$ORIG_GIT_DIR" || {
554582
GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR
555583
}
@@ -561,6 +589,58 @@ test -z "$ORIG_GIT_INDEX_FILE" || {
561589
GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" &&
562590
export GIT_INDEX_FILE
563591
}
592+
test -z "$ORIG_GIT_AUTHOR_NAME" || {
593+
GIT_AUTHOR_NAME="$ORIG_GIT_AUTHOR_NAME" &&
594+
export GIT_AUTHOR_NAME
595+
}
596+
test -z "$ORIG_GIT_AUTHOR_EMAIL" || {
597+
GIT_AUTHOR_EMAIL="$ORIG_GIT_AUTHOR_EMAIL" &&
598+
export GIT_AUTHOR_EMAIL
599+
}
600+
test -z "$ORIG_GIT_AUTHOR_DATE" || {
601+
GIT_AUTHOR_DATE="$ORIG_GIT_AUTHOR_DATE" &&
602+
export GIT_AUTHOR_DATE
603+
}
604+
test -z "$ORIG_GIT_COMMITTER_NAME" || {
605+
GIT_COMMITTER_NAME="$ORIG_GIT_COMMITTER_NAME" &&
606+
export GIT_COMMITTER_NAME
607+
}
608+
test -z "$ORIG_GIT_COMMITTER_EMAIL" || {
609+
GIT_COMMITTER_EMAIL="$ORIG_GIT_COMMITTER_EMAIL" &&
610+
export GIT_COMMITTER_EMAIL
611+
}
612+
test -z "$ORIG_GIT_COMMITTER_DATE" || {
613+
GIT_COMMITTER_DATE="$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+
643+
trap - 0
564644

565645
if [ "$(is_bare_repository)" = false ]; then
566646
git read-tree -u -m HEAD || exit

0 commit comments

Comments
 (0)