Teach filter-branch about subdirectory filtering
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Fri, 8 Jun 2007 00:30:35 +0000 (01:30 +0100)
committerJunio C Hamano <gitster@pobox.com>
Sat, 9 Jun 2007 19:16:49 +0000 (12:16 -0700)
With git-filter-branch --subdirectory-filter <subdirectory> you can
get at the history, as seen by a certain subdirectory. The history
of the rewritten branch will only contain commits that touched that
subdirectory, and the subdirectory will be rewritten to be the new
project root.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
git-filter-branch.sh
t/t7003-filter-branch.sh

index 9d61b7fff6670bcf40e4135749cec9bdb3fd10ae..efb8f2dbca9c347395557bdc178b8a256e266eb5 100755 (executable)
 #      attached, the rewritten tag won't have it. Sorry. (It is by
 #      definition impossible to preserve signatures at any rate, though.)
 #
+# --subdirectory-filter DIRECTORY:: Only regard the history, as seen by
+#      the given subdirectory. The result will contain that directory as
+#      its project root.
+#
 # EXAMPLE USAGE
 # -------------
 # Suppose you want to remove a file (containing confidential information
@@ -224,7 +228,13 @@ set_ident () {
 
 # list all parent's object names for a given commit
 get_parents () {
-       git-rev-list -1 --parents "$1" | sed "s/^[0-9a-f]*//"
+       case "$filter_subdir" in
+       "")
+               git-rev-list -1 --parents "$1"
+               ;;
+       *)
+               git-rev-list -1 --parents "$1" -- "$filter_subdir"
+       esac | sed "s/^[0-9a-f]*//"
 }
 
 tempdir=.git-rewrite
@@ -235,6 +245,7 @@ filter_parent=
 filter_msg=cat
 filter_commit='git-commit-tree "$@"'
 filter_tag_name=
+filter_subdir=
 while case "$#" in 0) usage;; esac
 do
        case "$1" in
@@ -280,6 +291,9 @@ do
        --tag-name-filter)
                filter_tag_name="$OPTARG"
                ;;
+       --subdirectory-filter)
+               filter_subdir="$OPTARG"
+               ;;
        *)
                usage
                ;;
@@ -313,7 +327,14 @@ ret=0
 
 mkdir ../map # map old->new commit ids for rewriting parents
 
-git-rev-list --reverse --topo-order --default HEAD "$@" >../revs
+case "$filter_subdir" in
+"")
+       git-rev-list --reverse --topo-order --default HEAD "$@"
+       ;;
+*)
+       git-rev-list --reverse --topo-order --default HEAD "$@" \
+               -- "$filter_subdir"
+esac > ../revs
 commits=$(cat ../revs | wc -l | tr -d " ")
 
 test $commits -eq 0 && die "Found nothing to rewrite"
@@ -323,7 +344,13 @@ while read commit; do
        i=$(($i+1))
        printf "$commit ($i/$commits) "
 
-       git-read-tree -i -m $commit
+       case "$filter_subdir" in
+       "")
+               git-read-tree -i -m $commit
+               ;;
+       *)
+               git-read-tree -i -m $commit:"$filter_subdir"
+       esac
 
        export GIT_COMMIT=$commit
        git-cat-file commit "$commit" >../commit
index 3739cb191d2c3875e201f4a110af57b444f4d3a1..292b83766d3de23cba5112af8ef8740f8839d92b 100755 (executable)
@@ -54,4 +54,28 @@ test_expect_success 'common ancestor is still common (unchanged)' '
        test "$(git-merge-base modD D)" = "$(git-rev-parse B)"
 '
 
+test_expect_success 'filter subdirectory only' '
+       mkdir subdir &&
+       touch subdir/new &&
+       git add subdir/new &&
+       test_tick &&
+       git commit -m "subdir" &&
+       echo H > a &&
+       test_tick &&
+       git commit -m "not subdir" a &&
+       echo A > subdir/new &&
+       test_tick &&
+       git commit -m "again subdir" subdir/new &&
+       git rm a &&
+       test_tick &&
+       git commit -m "again not subdir" &&
+       git-filter-branch --subdirectory-filter subdir sub
+'
+
+test_expect_success 'subdirectory filter result looks okay' '
+       test 2 = $(git-rev-list sub | wc -l) &&
+       git show sub:new &&
+       ! git show sub:subdir
+'
+
 test_done