Skip to content

Commit aa43779

Browse files
committed
Merge branch 'tr/filter-branch'
* tr/filter-branch: filter-branch: nearest-ancestor rewriting outside subdir filter filter-branch: stop special-casing $filter_subdir argument
2 parents 1973b23 + f2f3a6b commit aa43779

File tree

3 files changed

+58
-13
lines changed

3 files changed

+58
-13
lines changed

Documentation/git-filter-branch.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,18 @@ to other tags will be rewritten to point to the underlying commit.
159159
--subdirectory-filter <directory>::
160160
Only look at the history which touches the given subdirectory.
161161
The result will contain that directory (and only that) as its
162-
project root.
162+
project root. Implies --remap-to-ancestor.
163+
164+
--remap-to-ancestor::
165+
Rewrite refs to the nearest rewritten ancestor instead of
166+
ignoring them.
167+
+
168+
Normally, positive refs on the command line are only changed if the
169+
commit they point to was rewritten. However, you can limit the extent
170+
of this rewriting by using linkgit:rev-list[1] arguments, e.g., path
171+
limiters. Refs pointing to such excluded commits would then normally
172+
be ignored. With this option, they are instead rewritten to point at
173+
the nearest ancestor that was not excluded.
163174

164175
--prune-empty::
165176
Some kind of filters will generate empty commits, that left the tree

git-filter-branch.sh

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ filter_subdir=
125125
orig_namespace=refs/original/
126126
force=
127127
prune_empty=
128+
remap_to_ancestor=
128129
while :
129130
do
130131
case "$1" in
@@ -137,6 +138,11 @@ do
137138
force=t
138139
continue
139140
;;
141+
--remap-to-ancestor)
142+
shift
143+
remap_to_ancestor=t
144+
continue
145+
;;
140146
--prune-empty)
141147
shift
142148
prune_empty=t
@@ -182,6 +188,7 @@ do
182188
;;
183189
--subdirectory-filter)
184190
filter_subdir="$OPTARG"
191+
remap_to_ancestor=t
185192
;;
186193
--original)
187194
orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
@@ -257,15 +264,24 @@ git read-tree || die "Could not seed the index"
257264
# map old->new commit ids for rewriting parents
258265
mkdir ../map || die "Could not create map/ directory"
259266

267+
# we need "--" only if there are no path arguments in $@
268+
nonrevs=$(git rev-parse --no-revs "$@") || exit
269+
test -z "$nonrevs" && dashdash=-- || dashdash=
270+
rev_args=$(git rev-parse --revs-only "$@")
271+
260272
case "$filter_subdir" in
261273
"")
262-
git rev-list --reverse --topo-order --default HEAD \
263-
--parents --simplify-merges "$@"
274+
eval set -- "$(git rev-parse --sq --no-revs "$@")"
264275
;;
265276
*)
266-
git rev-list --reverse --topo-order --default HEAD \
267-
--parents --simplify-merges "$@" -- "$filter_subdir"
268-
esac > ../revs || die "Could not get the commits"
277+
eval set -- "$(git rev-parse --sq --no-revs "$@" $dashdash \
278+
"$filter_subdir")"
279+
;;
280+
esac
281+
282+
git rev-list --reverse --topo-order --default HEAD \
283+
--parents --simplify-merges $rev_args "$@" > ../revs ||
284+
die "Could not get the commits"
269285
commits=$(wc -l <../revs | tr -d " ")
270286

271287
test $commits -eq 0 && die "Found nothing to rewrite"
@@ -345,19 +361,19 @@ while read commit parents; do
345361
die "could not write rewritten commit"
346362
done <../revs
347363

348-
# In case of a subdirectory filter, it is possible that a specified head
349-
# is not in the set of rewritten commits, because it was pruned by the
350-
# revision walker. Fix it by mapping these heads to the unique nearest
351-
# ancestor that survived the pruning.
364+
# If we are filtering for paths, as in the case of a subdirectory
365+
# filter, it is possible that a specified head is not in the set of
366+
# rewritten commits, because it was pruned by the revision walker.
367+
# Ancestor remapping fixes this by mapping these heads to the unique
368+
# nearest ancestor that survived the pruning.
352369

353-
if test "$filter_subdir"
370+
if test "$remap_to_ancestor" = t
354371
then
355372
while read ref
356373
do
357374
sha1=$(git rev-parse "$ref"^0)
358375
test -f "$workdir"/../map/$sha1 && continue
359-
ancestor=$(git rev-list --simplify-merges -1 \
360-
$ref -- "$filter_subdir")
376+
ancestor=$(git rev-list --simplify-merges -1 "$ref" "$@")
361377
test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
362378
done < "$tempdir"/heads
363379
fi

t/t7003-filter-branch.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,4 +288,22 @@ test_expect_success 'Prune empty commits' '
288288
test_cmp expect actual
289289
'
290290

291+
test_expect_success '--remap-to-ancestor with filename filters' '
292+
git checkout master &&
293+
git reset --hard A &&
294+
test_commit add-foo foo 1 &&
295+
git branch moved-foo &&
296+
test_commit add-bar bar a &&
297+
git branch invariant &&
298+
orig_invariant=$(git rev-parse invariant) &&
299+
git branch moved-bar &&
300+
test_commit change-foo foo 2 &&
301+
git filter-branch -f --remap-to-ancestor \
302+
moved-foo moved-bar A..master \
303+
-- -- foo &&
304+
test $(git rev-parse moved-foo) = $(git rev-parse moved-bar) &&
305+
test $(git rev-parse moved-foo) = $(git rev-parse master^) &&
306+
test $orig_invariant = $(git rev-parse invariant)
307+
'
308+
291309
test_done

0 commit comments

Comments
 (0)