summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2009-11-20 23:46:14 -0800
committerJunio C Hamano <gitster@pobox.com>2009-11-20 23:46:14 -0800
commitaa437791d8b3d5a163777d1cabd1f299654ce712 (patch)
treec34b1714c6a80d0684e74bc96bdf47a263ea6ff4
parent1973b23d284d0473795798d208f4b2fe09c0e659 (diff)
parentf2f3a6b802e3dae09a1c414cd8516ff2a546a527 (diff)
downloadgit-aa437791d8b3d5a163777d1cabd1f299654ce712.tar.gz
Merge branch 'tr/filter-branch'
* tr/filter-branch: filter-branch: nearest-ancestor rewriting outside subdir filter filter-branch: stop special-casing $filter_subdir argument
-rw-r--r--Documentation/git-filter-branch.txt13
-rwxr-xr-xgit-filter-branch.sh40
-rwxr-xr-xt/t7003-filter-branch.sh18
3 files changed, 58 insertions, 13 deletions
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 2b40babb6b..394a77a35f 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -159,7 +159,18 @@ to other tags will be rewritten to point to the underlying commit.
--subdirectory-filter <directory>::
Only look at the history which touches the given subdirectory.
The result will contain that directory (and only that) as its
- project root.
+ project root. Implies --remap-to-ancestor.
+
+--remap-to-ancestor::
+ Rewrite refs to the nearest rewritten ancestor instead of
+ ignoring them.
++
+Normally, positive refs on the command line are only changed if the
+commit they point to was rewritten. However, you can limit the extent
+of this rewriting by using linkgit:rev-list[1] arguments, e.g., path
+limiters. Refs pointing to such excluded commits would then normally
+be ignored. With this option, they are instead rewritten to point at
+the nearest ancestor that was not excluded.
--prune-empty::
Some kind of filters will generate empty commits, that left the tree
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index a480d6fc70..6b8b6a4f26 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -125,6 +125,7 @@ filter_subdir=
orig_namespace=refs/original/
force=
prune_empty=
+remap_to_ancestor=
while :
do
case "$1" in
@@ -137,6 +138,11 @@ do
force=t
continue
;;
+ --remap-to-ancestor)
+ shift
+ remap_to_ancestor=t
+ continue
+ ;;
--prune-empty)
shift
prune_empty=t
@@ -182,6 +188,7 @@ do
;;
--subdirectory-filter)
filter_subdir="$OPTARG"
+ remap_to_ancestor=t
;;
--original)
orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
@@ -257,15 +264,24 @@ git read-tree || die "Could not seed the index"
# map old->new commit ids for rewriting parents
mkdir ../map || die "Could not create map/ directory"
+# we need "--" only if there are no path arguments in $@
+nonrevs=$(git rev-parse --no-revs "$@") || exit
+test -z "$nonrevs" && dashdash=-- || dashdash=
+rev_args=$(git rev-parse --revs-only "$@")
+
case "$filter_subdir" in
"")
- git rev-list --reverse --topo-order --default HEAD \
- --parents --simplify-merges "$@"
+ eval set -- "$(git rev-parse --sq --no-revs "$@")"
;;
*)
- git rev-list --reverse --topo-order --default HEAD \
- --parents --simplify-merges "$@" -- "$filter_subdir"
-esac > ../revs || die "Could not get the commits"
+ eval set -- "$(git rev-parse --sq --no-revs "$@" $dashdash \
+ "$filter_subdir")"
+ ;;
+esac
+
+git rev-list --reverse --topo-order --default HEAD \
+ --parents --simplify-merges $rev_args "$@" > ../revs ||
+ die "Could not get the commits"
commits=$(wc -l <../revs | tr -d " ")
test $commits -eq 0 && die "Found nothing to rewrite"
@@ -345,19 +361,19 @@ while read commit parents; do
die "could not write rewritten commit"
done <../revs
-# In case of a subdirectory filter, it is possible that a specified head
-# is not in the set of rewritten commits, because it was pruned by the
-# revision walker. Fix it by mapping these heads to the unique nearest
-# ancestor that survived the pruning.
+# If we are filtering for paths, as in the case of a subdirectory
+# filter, it is possible that a specified head is not in the set of
+# rewritten commits, because it was pruned by the revision walker.
+# Ancestor remapping fixes this by mapping these heads to the unique
+# nearest ancestor that survived the pruning.
-if test "$filter_subdir"
+if test "$remap_to_ancestor" = t
then
while read ref
do
sha1=$(git rev-parse "$ref"^0)
test -f "$workdir"/../map/$sha1 && continue
- ancestor=$(git rev-list --simplify-merges -1 \
- $ref -- "$filter_subdir")
+ ancestor=$(git rev-list --simplify-merges -1 "$ref" "$@")
test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
done < "$tempdir"/heads
fi
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 329c851685..9503875e97 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -288,4 +288,22 @@ test_expect_success 'Prune empty commits' '
test_cmp expect actual
'
+test_expect_success '--remap-to-ancestor with filename filters' '
+ git checkout master &&
+ git reset --hard A &&
+ test_commit add-foo foo 1 &&
+ git branch moved-foo &&
+ test_commit add-bar bar a &&
+ git branch invariant &&
+ orig_invariant=$(git rev-parse invariant) &&
+ git branch moved-bar &&
+ test_commit change-foo foo 2 &&
+ git filter-branch -f --remap-to-ancestor \
+ moved-foo moved-bar A..master \
+ -- -- foo &&
+ test $(git rev-parse moved-foo) = $(git rev-parse moved-bar) &&
+ test $(git rev-parse moved-foo) = $(git rev-parse master^) &&
+ test $orig_invariant = $(git rev-parse invariant)
+'
+
test_done