git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] filter-branch: stop special-casing $filter_subdir argument
@ 2009-10-21 18:16 Thomas Rast
  2009-10-21 18:16 ` [PATCH 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
  2009-10-21 18:28 ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Thomas Rast
  0 siblings, 2 replies; 22+ messages in thread
From: Thomas Rast @ 2009-10-21 18:16 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

Handling $filter_subdir in the usual way requires a separate case at
every use, because the variable is empty when unused.  Furthermore,
the case for --subdirectory-filter supplies its own --, so the user
cannot provide one himself (though there is also very little point in
doing so).

Instead, tack the $filter_subdir onto $@ in the right place
automatically, and only use a -- if it was not already provided by the
user.

We set non_ref_args again after changing "$@"; the next patch wants to
use it again afterwards, so we better not leave a stale value in
there.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

This is preparatory for the next patch; introducing another 'case'
along the lines of the existing one annoyed me, so I went for this
instead.  I would greatly appreciate extra eyes on my use of 'eval'.
I originally expected this to work without eval, but apparently this
is how one does it.  Quoting rules in the shell are annoying.

Incidentally, the last hunk sneak fixes a previously unquoted use of
$ref that is my fault from back in a0e4639 (filter-branch: fix ref
rewriting with --subdirectory-filter, 2008-08-12).


 git-filter-branch.sh |   28 +++++++++++++++++++++-------
 1 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index a480d6f..3890c22 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -257,15 +257,29 @@ 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"
 
+non_ref_args=$(git rev-parse --no-revs --sq "$@")
+dashdash=--
+for arg in "$non_ref_args"; do
+	if test arg = --; then
+		dashdash=
+		break
+	fi
+done
+
 case "$filter_subdir" in
 "")
-	git rev-list --reverse --topo-order --default HEAD \
-		--parents --simplify-merges "$@"
+	filter_subdir_sq=
 	;;
 *)
-	git rev-list --reverse --topo-order --default HEAD \
-		--parents --simplify-merges "$@" -- "$filter_subdir"
-esac > ../revs || die "Could not get the commits"
+	filter_subdir_sq=$(git rev-parse --sq-quote "$filter_subdir")
+esac
+
+eval "set -- \"\$@\" $dashdash $filter_subdir_sq"
+non_ref_args=$(git rev-parse --no-revs --sq "$@")
+
+git rev-list --reverse --topo-order --default HEAD \
+	--parents --simplify-merges "$@" \
+	> ../revs || die "Could not get the commits"
 commits=$(wc -l <../revs | tr -d " ")
 
 test $commits -eq 0 && die "Found nothing to rewrite"
@@ -356,8 +370,8 @@ then
 	do
 		sha1=$(git rev-parse "$ref"^0)
 		test -f "$workdir"/../map/$sha1 && continue
-		ancestor=$(git rev-list --simplify-merges -1 \
-				$ref -- "$filter_subdir")
+		ancestor=$(eval "git rev-list --simplify-merges " \
+				"-1 \"$ref\" $non_ref_args")
 		test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
 	done < "$tempdir"/heads
 fi
-- 
1.6.5.1.139.g12527

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter
  2009-10-21 18:16 [PATCH 1/2] filter-branch: stop special-casing $filter_subdir argument Thomas Rast
@ 2009-10-21 18:16 ` Thomas Rast
  2009-10-21 18:28 ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Thomas Rast
  1 sibling, 0 replies; 22+ messages in thread
From: Thomas Rast @ 2009-10-21 18:16 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

Since a0e4639 (filter-branch: fix ref rewriting with
--subdirectory-filter, 2008-08-12) git-filter-branch has done
nearest-ancestor rewriting when using a --subdirectory-filter.

However, that rewriting strategy is also a useful building block in
other tasks.  For example, if you want to split out a subset of files
from your history, you would typically call

  git filter-branch <refs> -- -- <files>

But this fails for all refs that do not point directly to a commit
that affects <files>, because their referenced commit will not be
rewritten and the ref remains untouched.

The code was already there for the --subdirectory-filter case, so just
introduce an option that enables it independently.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

This came up on IRC the other day (see a pattern?), when someone
wanted to split out the history for a single file, and first had to
point all relevant refs at the corresponding nearest relevant
ancestor.

I think we could even make this option the default if it wasn't for
backwards compatibility; after all, what use is rewriting the commits
if you do not get a ref pointing to them?


 Documentation/git-filter-branch.txt |   13 ++++++++++++-
 git-filter-branch.sh                |    7 ++++++-
 t/t7003-filter-branch.sh            |   18 ++++++++++++++++++
 3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 2b40bab..394a77a 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 3890c22..d18f82d 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
@@ -182,10 +183,14 @@ do
 		;;
 	--subdirectory-filter)
 		filter_subdir="$OPTARG"
+		remap_to_ancestor=t
 		;;
 	--original)
 		orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
 		;;
+	--remap-to-ancestor)
+		remap_to_ancestor=t
+		;;
 	*)
 		usage
 		;;
@@ -364,7 +369,7 @@ done <../revs
 # revision walker.  Fix it 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
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 329c851..9503875 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
-- 
1.6.5.1.139.g12527

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-10-21 18:16 [PATCH 1/2] filter-branch: stop special-casing $filter_subdir argument Thomas Rast
  2009-10-21 18:16 ` [PATCH 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
@ 2009-10-21 18:28 ` Thomas Rast
  2009-10-21 18:28   ` [PATCH v2 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
  2009-10-22  6:06   ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
  1 sibling, 2 replies; 22+ messages in thread
From: Thomas Rast @ 2009-10-21 18:28 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

Handling $filter_subdir in the usual way requires a separate case at
every use, because the variable is empty when unused.  Furthermore,
the case for --subdirectory-filter supplies its own --, so the user
cannot provide one himself (though there is also very little point in
doing so).

Instead, tack the $filter_subdir onto $@ in the right place
automatically, and only use a -- if it was not already provided by the
user.

We set non_ref_args again after changing "$@"; the next patch wants to
use it again afterwards, so we better not leave a stale value in
there.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

[Same as v1.]

This is preparatory for the next patch; introducing another 'case'
along the lines of the existing one annoyed me, so I went for this
instead.  I would greatly appreciate extra eyes on my use of 'eval'.
I originally expected this to work without eval, but apparently this
is how one does it.  Quoting rules in the shell are annoying.

Incidentally, the last hunk sneak fixes a previously unquoted use of
$ref that is my fault from back in a0e4639 (filter-branch: fix ref
rewriting with --subdirectory-filter, 2008-08-12).


 git-filter-branch.sh |   28 +++++++++++++++++++++-------
 1 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index a480d6f..3890c22 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -257,15 +257,29 @@ 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"
 
+non_ref_args=$(git rev-parse --no-revs --sq "$@")
+dashdash=--
+for arg in "$non_ref_args"; do
+	if test arg = --; then
+		dashdash=
+		break
+	fi
+done
+
 case "$filter_subdir" in
 "")
-	git rev-list --reverse --topo-order --default HEAD \
-		--parents --simplify-merges "$@"
+	filter_subdir_sq=
 	;;
 *)
-	git rev-list --reverse --topo-order --default HEAD \
-		--parents --simplify-merges "$@" -- "$filter_subdir"
-esac > ../revs || die "Could not get the commits"
+	filter_subdir_sq=$(git rev-parse --sq-quote "$filter_subdir")
+esac
+
+eval "set -- \"\$@\" $dashdash $filter_subdir_sq"
+non_ref_args=$(git rev-parse --no-revs --sq "$@")
+
+git rev-list --reverse --topo-order --default HEAD \
+	--parents --simplify-merges "$@" \
+	> ../revs || die "Could not get the commits"
 commits=$(wc -l <../revs | tr -d " ")
 
 test $commits -eq 0 && die "Found nothing to rewrite"
@@ -356,8 +370,8 @@ then
 	do
 		sha1=$(git rev-parse "$ref"^0)
 		test -f "$workdir"/../map/$sha1 && continue
-		ancestor=$(git rev-list --simplify-merges -1 \
-				$ref -- "$filter_subdir")
+		ancestor=$(eval "git rev-list --simplify-merges " \
+				"-1 \"$ref\" $non_ref_args")
 		test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
 	done < "$tempdir"/heads
 fi
-- 
1.6.5.1.142.g4bac9

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter
  2009-10-21 18:28 ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Thomas Rast
@ 2009-10-21 18:28   ` Thomas Rast
  2009-10-22  6:06   ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
  1 sibling, 0 replies; 22+ messages in thread
From: Thomas Rast @ 2009-10-21 18:28 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

Since a0e4639 (filter-branch: fix ref rewriting with
--subdirectory-filter, 2008-08-12) git-filter-branch has done
nearest-ancestor rewriting when using a --subdirectory-filter.

However, that rewriting strategy is also a useful building block in
other tasks.  For example, if you want to split out a subset of files
from your history, you would typically call

  git filter-branch -- <refs> -- <files>

But this fails for all refs that do not point directly to a commit
that affects <files>, because their referenced commit will not be
rewritten and the ref remains untouched.

The code was already there for the --subdirectory-filter case, so just
introduce an option that enables it independently.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

Evidently I shouldn't send any patches after dinner, or before, for
that matter (but for lack of wifi in the restaurant, *during* dinner
is not an option either).  Or at least I shouldn't re-read them after
sending :-(

v1 had a completely misplaced option parsing for the new option.
Very embarrassing.  Really.

I also sneak fixed the commit message above; you only need two -- if
you want rev-list options, e.g.,

  git filter-branch -- --all -- README

in which case the first one of course needs to appear before the first
<refs> argument.


 Documentation/git-filter-branch.txt |   13 ++++++++++++-
 git-filter-branch.sh                |    9 ++++++++-
 t/t7003-filter-branch.sh            |   18 ++++++++++++++++++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 2b40bab..394a77a 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 3890c22..be36db4 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/" : '\(.*[^/]\)/*$')/
@@ -364,7 +371,7 @@ done <../revs
 # revision walker.  Fix it 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
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 329c851..9503875 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
-- 
1.6.5.1.142.g4bac9

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-10-21 18:28 ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Thomas Rast
  2009-10-21 18:28   ` [PATCH v2 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
@ 2009-10-22  6:06   ` Johannes Sixt
  2009-10-22  8:05     ` Thomas Rast
  1 sibling, 1 reply; 22+ messages in thread
From: Johannes Sixt @ 2009-10-22  6:06 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

Thomas Rast schrieb:
> Handling $filter_subdir in the usual way requires a separate case at
> every use, because the variable is empty when unused.  Furthermore,
> the case for --subdirectory-filter supplies its own --, so the user
> cannot provide one himself (though there is also very little point in
> doing so).
> 
> Instead, tack the $filter_subdir onto $@ in the right place
> automatically, and only use a -- if it was not already provided by the
> user.

I understand that this is a preparatory patch, but you seem to argue that
even without the follow-up patch there is a problem. But from your
explanation I do not understand what it is. An example invocation that
shows the problem would be very helpful.

> @@ -257,15 +257,29 @@ 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"
>  
> +non_ref_args=$(git rev-parse --no-revs --sq "$@")
> +dashdash=--
> +for arg in "$non_ref_args"; do

At this point $non_ref_args might contain one or more IFS-separatable
words, but if you say "$non_ref_args" here, this loop will be entered
exactly once. But even if you drop the dquotes, the --sq quoting that you
requested from rev-parse bought you nothing.

> +	if test arg = --; then

Did you mean $arg here? Even then this test will succeed only if
$non_ref_args contains exactly one word and that word is '--'. Is that
what you mean?

> +		dashdash=
> +		break
> +	fi
> +done
> +
>  case "$filter_subdir" in
>  "")
> -	git rev-list --reverse --topo-order --default HEAD \
> -		--parents --simplify-merges "$@"
> +	filter_subdir_sq=
>  	;;
>  *)
> -	git rev-list --reverse --topo-order --default HEAD \
> -		--parents --simplify-merges "$@" -- "$filter_subdir"
> -esac > ../revs || die "Could not get the commits"
> +	filter_subdir_sq=$(git rev-parse --sq-quote "$filter_subdir")
> +esac
> +
> +eval "set -- \"\$@\" $dashdash $filter_subdir_sq"
> +non_ref_args=$(git rev-parse --no-revs --sq "$@")
> +
> +git rev-list --reverse --topo-order --default HEAD \
> +	--parents --simplify-merges "$@" \
> +	> ../revs || die "Could not get the commits"
>  commits=$(wc -l <../revs | tr -d " ")
>  
>  test $commits -eq 0 && die "Found nothing to rewrite"
> @@ -356,8 +370,8 @@ then
>  	do
>  		sha1=$(git rev-parse "$ref"^0)
>  		test -f "$workdir"/../map/$sha1 && continue
> -		ancestor=$(git rev-list --simplify-merges -1 \
> -				$ref -- "$filter_subdir")
> +		ancestor=$(eval "git rev-list --simplify-merges " \
> +				"-1 \"$ref\" $non_ref_args")
>  		test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
>  	done < "$tempdir"/heads
>  fi

This looks so convoluted; there must be a simpler way to achieve your goal.

-- Hannes

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-10-22  6:06   ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
@ 2009-10-22  8:05     ` Thomas Rast
  2009-10-22  8:31       ` Johannes Sixt
  0 siblings, 1 reply; 22+ messages in thread
From: Thomas Rast @ 2009-10-22  8:05 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: git, Junio C Hamano

Johannes Sixt wrote:
> Thomas Rast schrieb:
> > Handling $filter_subdir in the usual way requires a separate case at
> > every use, because the variable is empty when unused.  Furthermore,
> > the case for --subdirectory-filter supplies its own --, so the user
> > cannot provide one himself (though there is also very little point in
> > doing so).
> 
> I understand that this is a preparatory patch, but you seem to argue that
> even without the follow-up patch there is a problem. But from your
> explanation I do not understand what it is. An example invocation that
> shows the problem would be very helpful.

Well, I just observed while writing the patch that you cannot say

  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file

because the --subdirectory-filter supplies its own -- to the rev-list
invocation, i.e., it calls

  git rev-list --all -- subdir/file -- subdir

which filters for a file called --.

I doubt anyone ever needed this operation though, and it can easily be
done in two separate filtering steps.

> > @@ -257,15 +257,29 @@ 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"
> >  
> > +non_ref_args=$(git rev-parse --no-revs --sq "$@")
> > +dashdash=--
> > +for arg in "$non_ref_args"; do
> 
> At this point $non_ref_args might contain one or more IFS-separatable
> words, but if you say "$non_ref_args" here, this loop will be entered
> exactly once. But even if you drop the dquotes, the --sq quoting that you
> requested from rev-parse bought you nothing.

Hrm.  Ok, so the ".." were clearly in mistake, but why could I remove
the --sq?  Doesn't the shell expand the arguments provided by
$non_ref_args if I use it without quotes nor --sq, so that it might
accidentally expand paths or such?

> > +	if test arg = --; then
> 
> Did you mean $arg here? Even then this test will succeed only if
> $non_ref_args contains exactly one word and that word is '--'. Is that
> what you mean?

No, it should find a -- argument to see if we need to supply our own
before the $filter_subdir.

> This looks so convoluted; there must be a simpler way to achieve your goal.

I'll try with more 'case's later...  maybe I can at least avoid the
eval.

Thanks for your comments!

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-10-22  8:05     ` Thomas Rast
@ 2009-10-22  8:31       ` Johannes Sixt
  2009-10-28 22:59         ` [PATCH v3 " Thomas Rast
  0 siblings, 1 reply; 22+ messages in thread
From: Johannes Sixt @ 2009-10-22  8:31 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

Thomas Rast schrieb:
> Well, I just observed while writing the patch that you cannot say
> 
>   git filter-branch --subdirectory-filter subdir -- --all -- subdir/file

Please include this in the commit message.

> Johannes Sixt wrote:
>> Thomas Rast schrieb:
>>> @@ -257,15 +257,29 @@ 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"
>>>  
>>> +non_ref_args=$(git rev-parse --no-revs --sq "$@")
>>> +dashdash=--
>>> +for arg in "$non_ref_args"; do
>> At this point $non_ref_args might contain one or more IFS-separatable
>> words, but if you say "$non_ref_args" here, this loop will be entered
>> exactly once. But even if you drop the dquotes, the --sq quoting that you
>> requested from rev-parse bought you nothing.
> 
> Hrm.  Ok, so the ".." were clearly in mistake, but why could I remove
> the --sq?  Doesn't the shell expand the arguments provided by
> $non_ref_args if I use it without quotes nor --sq, so that it might
> accidentally expand paths or such?

When the shell expands $variable (outside quotes), it does not apply
quotes anymore, but only word-splits using $IFS. In your code, the words
would contain literal single-quotes, and paths with spaces would still be
split into words.

Wouldn't it be sufficient to just check whether any non-rev arguments are
present, and to suppress '--' if there are, like:

dashdash=
test -z "$(git rev-parse --no-revs "$@")" && dashdash=--

OK, this still leaves you with the problem that you want to separate
non-rev arguments from rev arguments. Right?

For this I suggest that you extract revs into a regular variable (because
the SHA1s can be word-split in a predictable way), and that you leave the
non-rev arguments in $@:

revs=$(git rev-parse --revs "$@")	# don't know if this works
eval set -- "$(git rev-parse --no-revs --sq "$@")"	# dquotes?

or so... This way you 'eval' should not be needed in later code.

-- Hannes

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-10-22  8:31       ` Johannes Sixt
@ 2009-10-28 22:59         ` Thomas Rast
  2009-10-28 22:59           ` [PATCH v3 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
  2009-10-29  7:35           ` [PATCH v3 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
  0 siblings, 2 replies; 22+ messages in thread
From: Thomas Rast @ 2009-10-28 22:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Johannes Sixt

Handling $filter_subdir in the usual way requires a separate case at
every use, because the variable is empty when unused.

Furthermore, the case for --subdirectory-filter supplies its own --,
so the user cannot provide one himself, so the following was
impossible:

  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file

To keep the argument handling sane, we filter $@ to contain only the
non-revision arguments, and store all revisions in $ref_args.  The
$ref_args are easy to handle since only the SHA1s are needed; the
actual branch names have already been stored in $tempdir/heads at this
point.

An extra separating -- is only required if the user did not provide
any non-revision arguments, as the latter disambiguate the
$filter_subdir following after them (or fail earlier because they are
ambiguous themselves).

Thanks to Johannes Sixt for suggesting this solution.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

Johannes Sixt wrote:
> When the shell expands $variable (outside quotes), it does not apply
> quotes anymore, but only word-splits using $IFS. In your code, the words
> would contain literal single-quotes, and paths with spaces would still be
> split into words.

If there's a good reason for these weird rules, I'm still missing
it...

But your suggestion works very nicely.

 git-filter-branch.sh |   21 ++++++++++++++-------
 1 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index a480d6f..da23b99 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -257,15 +257,23 @@ 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"
 
+dashdash=
+test -z "$(git rev-parse --no-revs "$@")" && dashdash=--
+ref_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 $ref_args "$@" \
+	> ../revs || die "Could not get the commits"
 commits=$(wc -l <../revs | tr -d " ")
 
 test $commits -eq 0 && die "Found nothing to rewrite"
@@ -356,8 +364,7 @@ then
 	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
-- 
1.6.5.1.161.g3b9c0

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter
  2009-10-28 22:59         ` [PATCH v3 " Thomas Rast
@ 2009-10-28 22:59           ` Thomas Rast
  2009-10-29  7:38             ` Johannes Sixt
  2009-10-29  7:35           ` [PATCH v3 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
  1 sibling, 1 reply; 22+ messages in thread
From: Thomas Rast @ 2009-10-28 22:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Johannes Sixt

Since a0e4639 (filter-branch: fix ref rewriting with
--subdirectory-filter, 2008-08-12) git-filter-branch has done
nearest-ancestor rewriting when using a --subdirectory-filter.

However, that rewriting strategy is also a useful building block in
other tasks.  For example, if you want to split out a subset of files
from your history, you would typically call

  git filter-branch -- <refs> -- <files>

But this fails for all refs that do not point directly to a commit
that affects <files>, because their referenced commit will not be
rewritten and the ref remains untouched.

The code was already there for the --subdirectory-filter case, so just
introduce an option that enables it independently.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

Same as v2.

 Documentation/git-filter-branch.txt |   13 ++++++++++++-
 git-filter-branch.sh                |    9 ++++++++-
 t/t7003-filter-branch.sh            |   18 ++++++++++++++++++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 2b40bab..394a77a 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 da23b99..ad2bc6f 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/" : '\(.*[^/]\)/*$')/
@@ -358,7 +365,7 @@ done <../revs
 # revision walker.  Fix it 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
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 329c851..9503875 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
-- 
1.6.5.1.161.g3b9c0

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-10-28 22:59         ` [PATCH v3 " Thomas Rast
  2009-10-28 22:59           ` [PATCH v3 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
@ 2009-10-29  7:35           ` Johannes Sixt
  2009-11-10 21:04             ` [PATCH v4 " Thomas Rast
  1 sibling, 1 reply; 22+ messages in thread
From: Johannes Sixt @ 2009-10-29  7:35 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

Thomas Rast schrieb:
> diff --git a/git-filter-branch.sh b/git-filter-branch.sh
> index a480d6f..da23b99 100755
> --- a/git-filter-branch.sh
> +++ b/git-filter-branch.sh
> @@ -257,15 +257,23 @@ 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"
>  
> +dashdash=
> +test -z "$(git rev-parse --no-revs "$@")" && dashdash=--

Hmm, if the user runs

   $ git filter-branch does-not-exist

then this would be the first call to rev-parse that fails with "fatal:
ambiguous argument 'does-not-exist': unknown revision or path...", but
this code wouldn't catch the failure. I suggest this instead:

# we need "--" only if there are no path arguments in $@
nonrevs=$(git rev-parse --no-revs "$@") || exit
dashdash=${nonrevs+"--"}

(including the comment; you can drop the dquotes in the dashdash
assignment if you think the result is still readable.)

I was to suggest to move these lines into the case arm below that is the
only user of $dashdash. But since this is a good error check of the
user-supplied arguments, I now prefer to keep the lines outside the case
statement.

> +ref_args=$(git rev-parse --revs-only "$@")

"ref_args"? Shouldn't it be "rev_args"? It's about "revisions", not
"references".

>  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"

This is not correct: $filter_subdir undergoes an extra level of
evaluation. You must write it like this:

	eval set -- "$(git rev-parse --sq --no-revs "$@" \
		$dashdash "$filter_subdir")"

> +	;;
> +esac
> +
> +git rev-list --reverse --topo-order --default HEAD \
> +	--parents --simplify-merges $ref_args "$@" \
> +	> ../revs || die "Could not get the commits"

Personally, I would prefer to write this as

git rev-list --reverse --topo-order --default HEAD \
	--parents --simplify-merges $ref_args "$@" > ../revs ||
	die "Could not get the commits"

to avoid one backslash.

> @@ -356,8 +364,7 @@ then
>  	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" "$@")

You added dquotes around $ref: while not absolutely necessary, I agree
with this change.

>  		test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
>  	done < "$tempdir"/heads
>  fi

-- Hannes

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter
  2009-10-28 22:59           ` [PATCH v3 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
@ 2009-10-29  7:38             ` Johannes Sixt
  0 siblings, 0 replies; 22+ messages in thread
From: Johannes Sixt @ 2009-10-29  7:38 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

Thomas Rast schrieb:
> @@ -358,7 +365,7 @@ done <../revs
>  # revision walker.  Fix it by mapping these heads to the unique nearest
>  # ancestor that survived the pruning.
>  
> -if test "$filter_subdir"
> +if test "$remap_to_ancestor" = t
>  then

The comment whose last lines are in the context of this hunk talks about
"subdirectory filter". You may want to revise it.

-- Hannes

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-10-29  7:35           ` [PATCH v3 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
@ 2009-11-10 21:04             ` Thomas Rast
  2009-11-10 21:04               ` [PATCH v4 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
  2009-11-11  8:30               ` [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
  0 siblings, 2 replies; 22+ messages in thread
From: Thomas Rast @ 2009-11-10 21:04 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Johannes Sixt

Handling $filter_subdir in the usual way requires a separate case at
every use, because the variable is empty when unused.

Furthermore, the case for --subdirectory-filter supplies its own --,
so the user cannot provide one himself, so the following was
impossible:

  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file

To keep the argument handling sane, we filter $@ to contain only the
non-revision arguments, and store all revisions in $ref_args.  The
$ref_args are easy to handle since only the SHA1s are needed; the
actual branch names have already been stored in $tempdir/heads at this
point.

An extra separating -- is only required if the user did not provide
any non-revision arguments, as the latter disambiguate the
$filter_subdir following after them (or fail earlier because they are
ambiguous themselves).

Thanks to Johannes Sixt for suggesting this solution.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

Thanks once again for your reviews.  It's been a while since I last
looked into this, but after some staring, I think you're right on all
counts.

Johannes Sixt wrote:
> # we need "--" only if there are no path arguments in $@
> nonrevs=$(git rev-parse --no-revs "$@") || exit
> dashdash=${nonrevs+"--"}
> 
> (including the comment; you can drop the dquotes in the dashdash
> assignment if you think the result is still readable.)

Ok.  I was briefly scared that this was bash-specific syntax, but dash
seems happy so I'll trust your advice.

> This is not correct: $filter_subdir undergoes an extra level of
> evaluation. You must write it like this:
> 
> 	eval set -- "$(git rev-parse --sq --no-revs "$@" \
> 		$dashdash "$filter_subdir")"

Hopefully I finally understand what's going on here.  The quoting
rules make my head spin.

> > -		ancestor=$(git rev-list --simplify-merges -1 \
> > -				$ref -- "$filter_subdir")
> > +		ancestor=$(git rev-list --simplify-merges -1 "$ref" "$@")
> 
> You added dquotes around $ref: while not absolutely necessary, I agree
> with this change.

It's kind of a sneak fix, but I broke this back in the ancestor
rewriting patch...  Luckily the refname sanity rules are designed to
prevent this from causing any harm.


 git-filter-branch.sh |   22 +++++++++++++++-------
 1 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index a480d6f..96b2182 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -257,15 +257,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
+dashdash=${nonrevs+"--"}
+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"
@@ -356,8 +365,7 @@ then
 	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
-- 
1.6.5.2.365.ge9237

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter
  2009-11-10 21:04             ` [PATCH v4 " Thomas Rast
@ 2009-11-10 21:04               ` Thomas Rast
  2009-11-11  8:30               ` [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
  1 sibling, 0 replies; 22+ messages in thread
From: Thomas Rast @ 2009-11-10 21:04 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Johannes Sixt

Since a0e4639 (filter-branch: fix ref rewriting with
--subdirectory-filter, 2008-08-12) git-filter-branch has done
nearest-ancestor rewriting when using a --subdirectory-filter.

However, that rewriting strategy is also a useful building block in
other tasks.  For example, if you want to split out a subset of files
from your history, you would typically call

  git filter-branch -- <refs> -- <files>

But this fails for all refs that do not point directly to a commit
that affects <files>, because their referenced commit will not be
rewritten and the ref remains untouched.

The code was already there for the --subdirectory-filter case, so just
introduce an option that enables it independently.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

Compared to v3 this only changes the comment, as suggested by Johannes
Sixt.


 Documentation/git-filter-branch.txt |   13 ++++++++++++-
 git-filter-branch.sh                |   18 +++++++++++++-----
 t/t7003-filter-branch.sh            |   18 ++++++++++++++++++
 3 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 2b40bab..394a77a 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 96b2182..a5a0352 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/" : '\(.*[^/]\)/*$')/
@@ -354,12 +361,13 @@ 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
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 329c851..9503875 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
-- 
1.6.5.2.365.ge9237

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-11-10 21:04             ` [PATCH v4 " Thomas Rast
  2009-11-10 21:04               ` [PATCH v4 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
@ 2009-11-11  8:30               ` Johannes Sixt
  2009-11-11  8:53                 ` [PATCH v5 " Johannes Sixt
  2009-11-11 18:00                 ` [PATCH v4 " Junio C Hamano
  1 sibling, 2 replies; 22+ messages in thread
From: Johannes Sixt @ 2009-11-11  8:30 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

Thomas Rast schrieb:
> Johannes Sixt wrote:
>> # we need "--" only if there are no path arguments in $@
>> nonrevs=$(git rev-parse --no-revs "$@") || exit
>> dashdash=${nonrevs+"--"}
>>
>> (including the comment; you can drop the dquotes in the dashdash
>> assignment if you think the result is still readable.)
> 
> Ok.  I was briefly scared that this was bash-specific syntax, but dash
> seems happy so I'll trust your advice.

You shouldn't. I'm wrong ;-)

In the snippet above, dashdash will always be set to "--" because a mere
'+' in the variable expansion only tests whether the variable ('nonrevs')
is unset, but it is always set. Even ${nonrevs:+"--"} is wrong, and your
earlier 'test -z' invocation was the correct way to set dashdash.

But...

I did some testing, and now I have to wonder about the use-case that you
present in the commit message:

> Furthermore, the case for --subdirectory-filter supplies its own --,
> so the user cannot provide one himself, so the following was
> impossible:
>
>   git filter-branch --subdirectory-filter subdir -- --all -- subdir/file

If you try in git.git itself:

  $ git rev-list --simplify-merges --all -- \
	Documentation/git-commit.txt | wc -l
  84
  $ git rev-list --simplify-merges --all -- \
	Documentation/git-commit.txt Documentation | wc -l
  4624

I thought that the intention to give an extra path argument is to reduce
the number of commits that remain in the rewritten history. But by giving
--subdirectory-filter, the path filter actually loosened, and many more
commits are rewritten.

Since your intention to write this patch is actually to implement
--remap-to-ancestor, I suggest that we defer the question whether the
above use-case makes sense, and only rewrite this particular paragraph in
the commit message to point out the real bug:

-----
Furthermore, --subdirectory-filter supplies its own '--', and if the user
provided one himself, such as in

  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file

an extra '--' was used as path filter in the call to git-rev-list that
determines the commits that shall be rewritten.
-----

I'll submit a replacement patch.

-- Hannes

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-11-11  8:30               ` [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
@ 2009-11-11  8:53                 ` Johannes Sixt
  2009-11-11  8:55                   ` [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Johannes Sixt
                                     ` (2 more replies)
  2009-11-11 18:00                 ` [PATCH v4 " Junio C Hamano
  1 sibling, 3 replies; 22+ messages in thread
From: Johannes Sixt @ 2009-11-11  8:53 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

From: Thomas Rast <trast@student.ethz.ch>

Handling $filter_subdir in the usual way requires a separate case at
every use, because the variable is empty when unused.

Furthermore, --subdirectory-filter supplies its own '--', and if the user
provided one himself, such as in

  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file

	an extra '--' was used as path filter in the call to git-rev-list that
determines the commits that shall be rewritten.

To keep the argument handling sane, we filter $@ to contain only the
non-revision arguments, and store all revisions in $ref_args.  The
$ref_args are easy to handle since only the SHA1s are needed; the
actual branch names have already been stored in $tempdir/heads at this
point.

An extra separating -- is only required if the user did not provide
any non-revision arguments, as the latter disambiguate the
$filter_subdir following after them (or fail earlier because they are
ambiguous themselves).

Thanks to Johannes Sixt for suggesting this solution.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
---
Johannes Sixt schrieb:
> I'll submit a replacement patch.

Here it is. The interdiff to your version is merely

--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -266,7 +266,7 @@

 # we need "--" only if there are no path arguments in $@
 nonrevs=$(git rev-parse --no-revs "$@") || exit
-dashdash=${nonrevs+"--"}
+test -z "$nonrevs" && dashdash=-- || dashdash=
 rev_args=$(git rev-parse --revs-only "$@")

 case "$filter_subdir" in

and I changed the commit message in the way I announced it.

-- Hannes

 git-filter-branch.sh |   22 +++++++++++++++-------
 1 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index a480d6f..ed3db7d 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -257,15 +257,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"
@@ -356,8 +365,7 @@ then
 	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
-- 
1.6.5.rc2.47.g49402

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter
  2009-11-11  8:53                 ` [PATCH v5 " Johannes Sixt
@ 2009-11-11  8:55                   ` Johannes Sixt
  2009-11-11 18:22                     ` Junio C Hamano
  2009-11-11  8:58                   ` [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
  2009-11-11 10:24                   ` Thomas Rast
  2 siblings, 1 reply; 22+ messages in thread
From: Johannes Sixt @ 2009-11-11  8:55 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

From: Thomas Rast <trast@student.ethz.ch>
Date: Tue, 10 Nov 2009 22:04:51 +0100

Since a0e4639 (filter-branch: fix ref rewriting with
--subdirectory-filter, 2008-08-12) git-filter-branch has done
nearest-ancestor rewriting when using a --subdirectory-filter.

However, that rewriting strategy is also a useful building block in
other tasks.  For example, if you want to split out a subset of files
from your history, you would typically call

  git filter-branch -- <refs> -- <files>

But this fails for all refs that do not point directly to a commit
that affects <files>, because their referenced commit will not be
rewritten and the ref remains untouched.

The code was already there for the --subdirectory-filter case, so just
introduce an option that enables it independently.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
---

Only resent for Junio's convenience. It is identical to your v4, but
with my SOB added.

-- Hannes

 Documentation/git-filter-branch.txt |   13 ++++++++++++-
 git-filter-branch.sh                |   18 +++++++++++++-----
 t/t7003-filter-branch.sh            |   18 ++++++++++++++++++
 3 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 2b40bab..394a77a 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 ed3db7d..6b8b6a4 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/" : '\(.*[^/]\)/*$')/
@@ -354,12 +361,13 @@ 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
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 329c851..9503875 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
-- 
1.6.5.rc2.47.g49402

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-11-11  8:53                 ` [PATCH v5 " Johannes Sixt
  2009-11-11  8:55                   ` [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Johannes Sixt
@ 2009-11-11  8:58                   ` Johannes Sixt
  2009-11-11 10:24                   ` Thomas Rast
  2 siblings, 0 replies; 22+ messages in thread
From: Johannes Sixt @ 2009-11-11  8:58 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

Johannes Sixt schrieb:
> --- a/git-filter-branch.sh
> +++ b/git-filter-branch.sh
> @@ -266,7 +266,7 @@
> 
>  # we need "--" only if there are no path arguments in $@
>  nonrevs=$(git rev-parse --no-revs "$@") || exit
> -dashdash=${nonrevs+"--"}
> +test -z "$nonrevs" && dashdash=-- || dashdash=
>  rev_args=$(git rev-parse --revs-only "$@")
> 
>  case "$filter_subdir" in

Arrgh! I should have indented these lines so that they
do not count as patch text.

Sorry.

-- Hannes

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-11-11  8:53                 ` [PATCH v5 " Johannes Sixt
  2009-11-11  8:55                   ` [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Johannes Sixt
  2009-11-11  8:58                   ` [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
@ 2009-11-11 10:24                   ` Thomas Rast
  2009-11-11 12:10                     ` Johannes Sixt
  2 siblings, 1 reply; 22+ messages in thread
From: Thomas Rast @ 2009-11-11 10:24 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: git, Junio C Hamano

Johannes Sixt wrote in the other reply:
> I thought that the intention to give an extra path argument is to reduce
> the number of commits that remain in the rewritten history. But by giving
> --subdirectory-filter, the path filter actually loosened, and many more
> commits are rewritten.

Right, I had a thinko there, the path filter adds up as an "or", so
filtering for paths outside the subdir loosens it (and filtering for
more paths inside doesn't make a difference).

> Since your intention to write this patch is actually to implement
> --remap-to-ancestor, I suggest that we defer the question whether the
> above use-case makes sense, and only rewrite this particular paragraph in
> the commit message to point out the real bug:

Agreed.

Johannes Sixt wrote:
> Furthermore, --subdirectory-filter supplies its own '--', and if the user
> provided one himself, such as in
> 
>   git filter-branch --subdirectory-filter subdir -- --all -- subdir/file
> 
> 	an extra '--' was used as path filter in the call to git-rev-list that
> determines the commits that shall be rewritten.

There's some stray space here that should probably also be removed.

> Here it is. The interdiff to your version is merely
[...]
>  # we need "--" only if there are no path arguments in $@
>  nonrevs=$(git rev-parse --no-revs "$@") || exit
> -dashdash=${nonrevs+"--"}
> +test -z "$nonrevs" && dashdash=-- || dashdash=

Ack.

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-11-11 10:24                   ` Thomas Rast
@ 2009-11-11 12:10                     ` Johannes Sixt
  0 siblings, 0 replies; 22+ messages in thread
From: Johannes Sixt @ 2009-11-11 12:10 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Junio C Hamano

Thomas Rast schrieb:
> Johannes Sixt wrote:
>> Furthermore, --subdirectory-filter supplies its own '--', and if the user
>> provided one himself, such as in
>>
>>   git filter-branch --subdirectory-filter subdir -- --all -- subdir/file
>>
>> 	an extra '--' was used as path filter in the call to git-rev-list that
>> determines the commits that shall be rewritten.
> 
> There's some stray space here that should probably also be removed.

Oh, right. Junio, you can pick up the 2-patch series from

  git://repo.or.cz/git/mingw/j6t.git filter-branch

-- Hannes

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument
  2009-11-11  8:30               ` [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
  2009-11-11  8:53                 ` [PATCH v5 " Johannes Sixt
@ 2009-11-11 18:00                 ` Junio C Hamano
  1 sibling, 0 replies; 22+ messages in thread
From: Junio C Hamano @ 2009-11-11 18:00 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: Thomas Rast, git, Junio C Hamano

Johannes Sixt <j.sixt@viscovery.net> writes:

> In the snippet above, dashdash will always be set to "--" because a mere
> '+' in the variable expansion only tests whether the variable ('nonrevs')
> is unset, but it is always set. Even ${nonrevs:+"--"} is wrong, and your
> earlier 'test -z' invocation was the correct way to set dashdash.

I do not mind "test -z", so this is just for information, but you could
use variable substitution with a colon, i.e. ${nonrevs:+"--"}.

IIRC, the colon-form ("do this if unset or empty") wasn't understood by
ancient BSDs but these days it is safe to use.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter
  2009-11-11  8:55                   ` [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Johannes Sixt
@ 2009-11-11 18:22                     ` Junio C Hamano
  2009-11-11 18:36                       ` Thomas Rast
  0 siblings, 1 reply; 22+ messages in thread
From: Junio C Hamano @ 2009-11-11 18:22 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: Thomas Rast, git, Junio C Hamano

Johannes Sixt <j.sixt@viscovery.net> writes:

> However, that rewriting strategy is also a useful building block in
> other tasks.  For example, if you want to split out a subset of files
> from your history, you would typically call
>
>   git filter-branch -- <refs> -- <files>
>
> But this fails for all refs that do not point directly to a commit
> that affects <files>, because their referenced commit will not be
> rewritten and the ref remains untouched.
>
> The code was already there for the --subdirectory-filter case, so just
> introduce an option that enables it independently.
>
> Signed-off-by: Thomas Rast <trast@student.ethz.ch>
> Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Up to this point, nothing mentions the name of the new option.  Please
write your log for a person who needs to write the release notes by
looking at "git shortlog" output ;-)

I am wondering if this even needs an option to trigger.  Shouldn't you
want this behaviour always when you give any pathspec?

What are the sane reasons to leave the rewritten ref to point at the old
commit, essentially making the rewritten history unreachable?

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter
  2009-11-11 18:22                     ` Junio C Hamano
@ 2009-11-11 18:36                       ` Thomas Rast
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Rast @ 2009-11-11 18:36 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Sixt, git

Junio C Hamano wrote:
> 
> Up to this point, nothing mentions the name of the new option.  Please
> write your log for a person who needs to write the release notes by
> looking at "git shortlog" output ;-)
> 
> I am wondering if this even needs an option to trigger.  Shouldn't you
> want this behaviour always when you give any pathspec?
> 
> What are the sane reasons to leave the rewritten ref to point at the old
> commit, essentially making the rewritten history unreachable?

Fear of hysterical raisins, nothing else.  I cannot really see a
use-case of the original behaviour, and since it does not change the
behaviour in the case of an unfiltered rewrite, it should be safe to
always be enabled.

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2009-11-11 18:37 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-10-21 18:16 [PATCH 1/2] filter-branch: stop special-casing $filter_subdir argument Thomas Rast
2009-10-21 18:16 ` [PATCH 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
2009-10-21 18:28 ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Thomas Rast
2009-10-21 18:28   ` [PATCH v2 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
2009-10-22  6:06   ` [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
2009-10-22  8:05     ` Thomas Rast
2009-10-22  8:31       ` Johannes Sixt
2009-10-28 22:59         ` [PATCH v3 " Thomas Rast
2009-10-28 22:59           ` [PATCH v3 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
2009-10-29  7:38             ` Johannes Sixt
2009-10-29  7:35           ` [PATCH v3 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
2009-11-10 21:04             ` [PATCH v4 " Thomas Rast
2009-11-10 21:04               ` [PATCH v4 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Thomas Rast
2009-11-11  8:30               ` [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
2009-11-11  8:53                 ` [PATCH v5 " Johannes Sixt
2009-11-11  8:55                   ` [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter Johannes Sixt
2009-11-11 18:22                     ` Junio C Hamano
2009-11-11 18:36                       ` Thomas Rast
2009-11-11  8:58                   ` [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument Johannes Sixt
2009-11-11 10:24                   ` Thomas Rast
2009-11-11 12:10                     ` Johannes Sixt
2009-11-11 18:00                 ` [PATCH v4 " Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).