{"thread":{"id":"21313","subject":"[PATCH 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","startedAt":"2009-10-21T18:16:21Z","lastAt":"2009-11-11T18:36:04Z","messageCount":22,"participants":["Thomas Rast","Johannes Sixt","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"125630","messageId":"95535b01e2181d321190c6d93b2834188612a389.1256148512.git.trast@student.ethz.ch","threadId":"21313","inReplyTo":null,"subject":"[PATCH 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-10-21T18:16:21Z","receivedAt":"2009-10-21T18:16:21Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Handling $filter_subdir in the usual way requires a separate case at\nevery use, because the variable is empty when unused.  Furthermore,\nthe case for --subdirectory-filter supplies its own --, so the user\ncannot provide one himself (though there is also very little point in\ndoing so).\n\nInstead, tack the $filter_subdir onto $@ in the right place\nautomatically, and only use a -- if it was not already provided by the\nuser.\n\nWe set non_ref_args again after changing \"$@\"; the next patch wants to\nuse it again afterwards, so we better not leave a stale value in\nthere.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nThis is preparatory for the next patch; introducing another 'case'\nalong the lines of the existing one annoyed me, so I went for this\ninstead.  I would greatly appreciate extra eyes on my use of 'eval'.\nI originally expected this to work without eval, but apparently this\nis how one does it.  Quoting rules in the shell are annoying.\n\nIncidentally, the last hunk sneak fixes a previously unquoted use of\n$ref that is my fault from back in a0e4639 (filter-branch: fix ref\nrewriting with --subdirectory-filter, 2008-08-12).\n\n\n git-filter-branch.sh |   28 +++++++++++++++++++++-------\n 1 files changed, 21 insertions(+), 7 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex a480d6f..3890c22 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -257,15 +257,29 @@ git read-tree || die \"Could not seed the index\"\n # map old->new commit ids for rewriting parents\n mkdir ../map || die \"Could not create map/ directory\"\n \n+non_ref_args=$(git rev-parse --no-revs --sq \"$@\")\n+dashdash=--\n+for arg in \"$non_ref_args\"; do\n+\tif test arg = --; then\n+\t\tdashdash=\n+\t\tbreak\n+\tfi\n+done\n+\n case \"$filter_subdir\" in\n \"\")\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\"\n+\tfilter_subdir_sq=\n \t;;\n *)\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\" -- \"$filter_subdir\"\n-esac > ../revs || die \"Could not get the commits\"\n+\tfilter_subdir_sq=$(git rev-parse --sq-quote \"$filter_subdir\")\n+esac\n+\n+eval \"set -- \\\"\\$@\\\" $dashdash $filter_subdir_sq\"\n+non_ref_args=$(git rev-parse --no-revs --sq \"$@\")\n+\n+git rev-list --reverse --topo-order --default HEAD \\\n+\t--parents --simplify-merges \"$@\" \\\n+\t> ../revs || die \"Could not get the commits\"\n commits=$(wc -l <../revs | tr -d \" \")\n \n test $commits -eq 0 && die \"Found nothing to rewrite\"\n@@ -356,8 +370,8 @@ then\n \tdo\n \t\tsha1=$(git rev-parse \"$ref\"^0)\n \t\ttest -f \"$workdir\"/../map/$sha1 && continue\n-\t\tancestor=$(git rev-list --simplify-merges -1 \\\n-\t\t\t\t$ref -- \"$filter_subdir\")\n+\t\tancestor=$(eval \"git rev-list --simplify-merges \" \\\n+\t\t\t\t\"-1 \\\"$ref\\\" $non_ref_args\")\n \t\ttest \"$ancestor\" && echo $(map $ancestor) >> \"$workdir\"/../map/$sha1\n \tdone < \"$tempdir\"/heads\n fi\n-- \n1.6.5.1.139.g12527\n"},{"id":"125629","messageId":"e1b4fcc7c167e8a7e49a2c2d6375045f6f481117.1256148512.git.trast@student.ethz.ch","threadId":"21313","inReplyTo":"95535b01e2181d321190c6d93b2834188612a389.1256148512.git.trast@student.ethz.ch","subject":"[PATCH 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-10-21T18:16:22Z","receivedAt":"2009-10-21T18:16:22Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Since a0e4639 (filter-branch: fix ref rewriting with\n--subdirectory-filter, 2008-08-12) git-filter-branch has done\nnearest-ancestor rewriting when using a --subdirectory-filter.\n\nHowever, that rewriting strategy is also a useful building block in\nother tasks.  For example, if you want to split out a subset of files\nfrom your history, you would typically call\n\n  git filter-branch <refs> -- -- <files>\n\nBut this fails for all refs that do not point directly to a commit\nthat affects <files>, because their referenced commit will not be\nrewritten and the ref remains untouched.\n\nThe code was already there for the --subdirectory-filter case, so just\nintroduce an option that enables it independently.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nThis came up on IRC the other day (see a pattern?), when someone\nwanted to split out the history for a single file, and first had to\npoint all relevant refs at the corresponding nearest relevant\nancestor.\n\nI think we could even make this option the default if it wasn't for\nbackwards compatibility; after all, what use is rewriting the commits\nif you do not get a ref pointing to them?\n\n\n Documentation/git-filter-branch.txt |   13 ++++++++++++-\n git-filter-branch.sh                |    7 ++++++-\n t/t7003-filter-branch.sh            |   18 ++++++++++++++++++\n 3 files changed, 36 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt\nindex 2b40bab..394a77a 100644\n--- a/Documentation/git-filter-branch.txt\n+++ b/Documentation/git-filter-branch.txt\n@@ -159,7 +159,18 @@ to other tags will be rewritten to point to the underlying commit.\n --subdirectory-filter <directory>::\n \tOnly look at the history which touches the given subdirectory.\n \tThe result will contain that directory (and only that) as its\n-\tproject root.\n+\tproject root.  Implies --remap-to-ancestor.\n+\n+--remap-to-ancestor::\n+\tRewrite refs to the nearest rewritten ancestor instead of\n+\tignoring them.\n++\n+Normally, positive refs on the command line are only changed if the\n+commit they point to was rewritten.  However, you can limit the extent\n+of this rewriting by using linkgit:rev-list[1] arguments, e.g., path\n+limiters.  Refs pointing to such excluded commits would then normally\n+be ignored.  With this option, they are instead rewritten to point at\n+the nearest ancestor that was not excluded.\n \n --prune-empty::\n \tSome kind of filters will generate empty commits, that left the tree\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 3890c22..d18f82d 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -125,6 +125,7 @@ filter_subdir=\n orig_namespace=refs/original/\n force=\n prune_empty=\n+remap_to_ancestor=\n while :\n do\n \tcase \"$1\" in\n@@ -182,10 +183,14 @@ do\n \t\t;;\n \t--subdirectory-filter)\n \t\tfilter_subdir=\"$OPTARG\"\n+\t\tremap_to_ancestor=t\n \t\t;;\n \t--original)\n \t\torig_namespace=$(expr \"$OPTARG/\" : '\\(.*[^/]\\)/*$')/\n \t\t;;\n+\t--remap-to-ancestor)\n+\t\tremap_to_ancestor=t\n+\t\t;;\n \t*)\n \t\tusage\n \t\t;;\n@@ -364,7 +369,7 @@ done <../revs\n # revision walker.  Fix it by mapping these heads to the unique nearest\n # ancestor that survived the pruning.\n \n-if test \"$filter_subdir\"\n+if test \"$remap_to_ancestor\" = t\n then\n \twhile read ref\n \tdo\ndiff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh\nindex 329c851..9503875 100755\n--- a/t/t7003-filter-branch.sh\n+++ b/t/t7003-filter-branch.sh\n@@ -288,4 +288,22 @@ test_expect_success 'Prune empty commits' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--remap-to-ancestor with filename filters' '\n+\tgit checkout master &&\n+\tgit reset --hard A &&\n+\ttest_commit add-foo foo 1 &&\n+\tgit branch moved-foo &&\n+\ttest_commit add-bar bar a &&\n+\tgit branch invariant &&\n+\torig_invariant=$(git rev-parse invariant) &&\n+\tgit branch moved-bar &&\n+\ttest_commit change-foo foo 2 &&\n+\tgit filter-branch -f --remap-to-ancestor \\\n+\t\tmoved-foo moved-bar A..master \\\n+\t\t-- -- foo &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse moved-bar) &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse master^) &&\n+\ttest $orig_invariant = $(git rev-parse invariant)\n+'\n+\n test_done\n-- \n1.6.5.1.139.g12527\n"},{"id":"125631","messageId":"95535b01e2181d321190c6d93b2834188612a389.1256149428.git.trast@student.ethz.ch","threadId":"21313","inReplyTo":"95535b01e2181d321190c6d93b2834188612a389.1256148512.git.trast@student.ethz.ch","subject":"[PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-10-21T18:28:50Z","receivedAt":"2009-10-21T18:28:50Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Handling $filter_subdir in the usual way requires a separate case at\nevery use, because the variable is empty when unused.  Furthermore,\nthe case for --subdirectory-filter supplies its own --, so the user\ncannot provide one himself (though there is also very little point in\ndoing so).\n\nInstead, tack the $filter_subdir onto $@ in the right place\nautomatically, and only use a -- if it was not already provided by the\nuser.\n\nWe set non_ref_args again after changing \"$@\"; the next patch wants to\nuse it again afterwards, so we better not leave a stale value in\nthere.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\n[Same as v1.]\n\nThis is preparatory for the next patch; introducing another 'case'\nalong the lines of the existing one annoyed me, so I went for this\ninstead.  I would greatly appreciate extra eyes on my use of 'eval'.\nI originally expected this to work without eval, but apparently this\nis how one does it.  Quoting rules in the shell are annoying.\n\nIncidentally, the last hunk sneak fixes a previously unquoted use of\n$ref that is my fault from back in a0e4639 (filter-branch: fix ref\nrewriting with --subdirectory-filter, 2008-08-12).\n\n\n git-filter-branch.sh |   28 +++++++++++++++++++++-------\n 1 files changed, 21 insertions(+), 7 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex a480d6f..3890c22 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -257,15 +257,29 @@ git read-tree || die \"Could not seed the index\"\n # map old->new commit ids for rewriting parents\n mkdir ../map || die \"Could not create map/ directory\"\n \n+non_ref_args=$(git rev-parse --no-revs --sq \"$@\")\n+dashdash=--\n+for arg in \"$non_ref_args\"; do\n+\tif test arg = --; then\n+\t\tdashdash=\n+\t\tbreak\n+\tfi\n+done\n+\n case \"$filter_subdir\" in\n \"\")\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\"\n+\tfilter_subdir_sq=\n \t;;\n *)\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\" -- \"$filter_subdir\"\n-esac > ../revs || die \"Could not get the commits\"\n+\tfilter_subdir_sq=$(git rev-parse --sq-quote \"$filter_subdir\")\n+esac\n+\n+eval \"set -- \\\"\\$@\\\" $dashdash $filter_subdir_sq\"\n+non_ref_args=$(git rev-parse --no-revs --sq \"$@\")\n+\n+git rev-list --reverse --topo-order --default HEAD \\\n+\t--parents --simplify-merges \"$@\" \\\n+\t> ../revs || die \"Could not get the commits\"\n commits=$(wc -l <../revs | tr -d \" \")\n \n test $commits -eq 0 && die \"Found nothing to rewrite\"\n@@ -356,8 +370,8 @@ then\n \tdo\n \t\tsha1=$(git rev-parse \"$ref\"^0)\n \t\ttest -f \"$workdir\"/../map/$sha1 && continue\n-\t\tancestor=$(git rev-list --simplify-merges -1 \\\n-\t\t\t\t$ref -- \"$filter_subdir\")\n+\t\tancestor=$(eval \"git rev-list --simplify-merges \" \\\n+\t\t\t\t\"-1 \\\"$ref\\\" $non_ref_args\")\n \t\ttest \"$ancestor\" && echo $(map $ancestor) >> \"$workdir\"/../map/$sha1\n \tdone < \"$tempdir\"/heads\n fi\n-- \n1.6.5.1.142.g4bac9\n"},{"id":"125632","messageId":"9676b8307ce61d9b3bf79beff7f4b9a04220154f.1256149428.git.trast@student.ethz.ch","threadId":"21313","inReplyTo":"95535b01e2181d321190c6d93b2834188612a389.1256149428.git.trast@student.ethz.ch","subject":"[PATCH v2 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-10-21T18:28:51Z","receivedAt":"2009-10-21T18:28:51Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Since a0e4639 (filter-branch: fix ref rewriting with\n--subdirectory-filter, 2008-08-12) git-filter-branch has done\nnearest-ancestor rewriting when using a --subdirectory-filter.\n\nHowever, that rewriting strategy is also a useful building block in\nother tasks.  For example, if you want to split out a subset of files\nfrom your history, you would typically call\n\n  git filter-branch -- <refs> -- <files>\n\nBut this fails for all refs that do not point directly to a commit\nthat affects <files>, because their referenced commit will not be\nrewritten and the ref remains untouched.\n\nThe code was already there for the --subdirectory-filter case, so just\nintroduce an option that enables it independently.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nEvidently I shouldn't send any patches after dinner, or before, for\nthat matter (but for lack of wifi in the restaurant, *during* dinner\nis not an option either).  Or at least I shouldn't re-read them after\nsending :-(\n\nv1 had a completely misplaced option parsing for the new option.\nVery embarrassing.  Really.\n\nI also sneak fixed the commit message above; you only need two -- if\nyou want rev-list options, e.g.,\n\n  git filter-branch -- --all -- README\n\nin which case the first one of course needs to appear before the first\n<refs> argument.\n\n\n Documentation/git-filter-branch.txt |   13 ++++++++++++-\n git-filter-branch.sh                |    9 ++++++++-\n t/t7003-filter-branch.sh            |   18 ++++++++++++++++++\n 3 files changed, 38 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt\nindex 2b40bab..394a77a 100644\n--- a/Documentation/git-filter-branch.txt\n+++ b/Documentation/git-filter-branch.txt\n@@ -159,7 +159,18 @@ to other tags will be rewritten to point to the underlying commit.\n --subdirectory-filter <directory>::\n \tOnly look at the history which touches the given subdirectory.\n \tThe result will contain that directory (and only that) as its\n-\tproject root.\n+\tproject root.  Implies --remap-to-ancestor.\n+\n+--remap-to-ancestor::\n+\tRewrite refs to the nearest rewritten ancestor instead of\n+\tignoring them.\n++\n+Normally, positive refs on the command line are only changed if the\n+commit they point to was rewritten.  However, you can limit the extent\n+of this rewriting by using linkgit:rev-list[1] arguments, e.g., path\n+limiters.  Refs pointing to such excluded commits would then normally\n+be ignored.  With this option, they are instead rewritten to point at\n+the nearest ancestor that was not excluded.\n \n --prune-empty::\n \tSome kind of filters will generate empty commits, that left the tree\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 3890c22..be36db4 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -125,6 +125,7 @@ filter_subdir=\n orig_namespace=refs/original/\n force=\n prune_empty=\n+remap_to_ancestor=\n while :\n do\n \tcase \"$1\" in\n@@ -137,6 +138,11 @@ do\n \t\tforce=t\n \t\tcontinue\n \t\t;;\n+\t--remap-to-ancestor)\n+\t\tshift\n+\t\tremap_to_ancestor=t\n+\t\tcontinue\n+\t\t;;\n \t--prune-empty)\n \t\tshift\n \t\tprune_empty=t\n@@ -182,6 +188,7 @@ do\n \t\t;;\n \t--subdirectory-filter)\n \t\tfilter_subdir=\"$OPTARG\"\n+\t\tremap_to_ancestor=t\n \t\t;;\n \t--original)\n \t\torig_namespace=$(expr \"$OPTARG/\" : '\\(.*[^/]\\)/*$')/\n@@ -364,7 +371,7 @@ done <../revs\n # revision walker.  Fix it by mapping these heads to the unique nearest\n # ancestor that survived the pruning.\n \n-if test \"$filter_subdir\"\n+if test \"$remap_to_ancestor\" = t\n then\n \twhile read ref\n \tdo\ndiff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh\nindex 329c851..9503875 100755\n--- a/t/t7003-filter-branch.sh\n+++ b/t/t7003-filter-branch.sh\n@@ -288,4 +288,22 @@ test_expect_success 'Prune empty commits' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--remap-to-ancestor with filename filters' '\n+\tgit checkout master &&\n+\tgit reset --hard A &&\n+\ttest_commit add-foo foo 1 &&\n+\tgit branch moved-foo &&\n+\ttest_commit add-bar bar a &&\n+\tgit branch invariant &&\n+\torig_invariant=$(git rev-parse invariant) &&\n+\tgit branch moved-bar &&\n+\ttest_commit change-foo foo 2 &&\n+\tgit filter-branch -f --remap-to-ancestor \\\n+\t\tmoved-foo moved-bar A..master \\\n+\t\t-- -- foo &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse moved-bar) &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse master^) &&\n+\ttest $orig_invariant = $(git rev-parse invariant)\n+'\n+\n test_done\n-- \n1.6.5.1.142.g4bac9\n"},{"id":"125674","messageId":"4ADFF66F.1080005@viscovery.net","threadId":"21313","inReplyTo":"95535b01e2181d321190c6d93b2834188612a389.1256149428.git.trast@student.ethz.ch","subject":"Re: [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-10-22T06:06:39Z","receivedAt":"2009-10-22T06:06:39Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Thomas Rast schrieb:\n> Handling $filter_subdir in the usual way requires a separate case at\n> every use, because the variable is empty when unused.  Furthermore,\n> the case for --subdirectory-filter supplies its own --, so the user\n> cannot provide one himself (though there is also very little point in\n> doing so).\n> \n> Instead, tack the $filter_subdir onto $@ in the right place\n> automatically, and only use a -- if it was not already provided by the\n> user.\n\nI understand that this is a preparatory patch, but you seem to argue that\neven without the follow-up patch there is a problem. But from your\nexplanation I do not understand what it is. An example invocation that\nshows the problem would be very helpful.\n\n> @@ -257,15 +257,29 @@ git read-tree || die \"Could not seed the index\"\n>  # map old->new commit ids for rewriting parents\n>  mkdir ../map || die \"Could not create map/ directory\"\n>  \n> +non_ref_args=$(git rev-parse --no-revs --sq \"$@\")\n> +dashdash=--\n> +for arg in \"$non_ref_args\"; do\n\nAt this point $non_ref_args might contain one or more IFS-separatable\nwords, but if you say \"$non_ref_args\" here, this loop will be entered\nexactly once. But even if you drop the dquotes, the --sq quoting that you\nrequested from rev-parse bought you nothing.\n\n> +\tif test arg = --; then\n\nDid you mean $arg here? Even then this test will succeed only if\n$non_ref_args contains exactly one word and that word is '--'. Is that\nwhat you mean?\n\n> +\t\tdashdash=\n> +\t\tbreak\n> +\tfi\n> +done\n> +\n>  case \"$filter_subdir\" in\n>  \"\")\n> -\tgit rev-list --reverse --topo-order --default HEAD \\\n> -\t\t--parents --simplify-merges \"$@\"\n> +\tfilter_subdir_sq=\n>  \t;;\n>  *)\n> -\tgit rev-list --reverse --topo-order --default HEAD \\\n> -\t\t--parents --simplify-merges \"$@\" -- \"$filter_subdir\"\n> -esac > ../revs || die \"Could not get the commits\"\n> +\tfilter_subdir_sq=$(git rev-parse --sq-quote \"$filter_subdir\")\n> +esac\n> +\n> +eval \"set -- \\\"\\$@\\\" $dashdash $filter_subdir_sq\"\n> +non_ref_args=$(git rev-parse --no-revs --sq \"$@\")\n> +\n> +git rev-list --reverse --topo-order --default HEAD \\\n> +\t--parents --simplify-merges \"$@\" \\\n> +\t> ../revs || die \"Could not get the commits\"\n>  commits=$(wc -l <../revs | tr -d \" \")\n>  \n>  test $commits -eq 0 && die \"Found nothing to rewrite\"\n> @@ -356,8 +370,8 @@ then\n>  \tdo\n>  \t\tsha1=$(git rev-parse \"$ref\"^0)\n>  \t\ttest -f \"$workdir\"/../map/$sha1 && continue\n> -\t\tancestor=$(git rev-list --simplify-merges -1 \\\n> -\t\t\t\t$ref -- \"$filter_subdir\")\n> +\t\tancestor=$(eval \"git rev-list --simplify-merges \" \\\n> +\t\t\t\t\"-1 \\\"$ref\\\" $non_ref_args\")\n>  \t\ttest \"$ancestor\" && echo $(map $ancestor) >> \"$workdir\"/../map/$sha1\n>  \tdone < \"$tempdir\"/heads\n>  fi\n\nThis looks so convoluted; there must be a simpler way to achieve your goal.\n\n-- Hannes\n"},{"id":"125685","messageId":"200910221005.11813.trast@student.ethz.ch","threadId":"21313","inReplyTo":"4ADFF66F.1080005@viscovery.net","subject":"Re: [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-10-22T08:05:10Z","receivedAt":"2009-10-22T08:05:10Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Johannes Sixt wrote:\n> Thomas Rast schrieb:\n> > Handling $filter_subdir in the usual way requires a separate case at\n> > every use, because the variable is empty when unused.  Furthermore,\n> > the case for --subdirectory-filter supplies its own --, so the user\n> > cannot provide one himself (though there is also very little point in\n> > doing so).\n> \n> I understand that this is a preparatory patch, but you seem to argue that\n> even without the follow-up patch there is a problem. But from your\n> explanation I do not understand what it is. An example invocation that\n> shows the problem would be very helpful.\n\nWell, I just observed while writing the patch that you cannot say\n\n  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n\nbecause the --subdirectory-filter supplies its own -- to the rev-list\ninvocation, i.e., it calls\n\n  git rev-list --all -- subdir/file -- subdir\n\nwhich filters for a file called --.\n\nI doubt anyone ever needed this operation though, and it can easily be\ndone in two separate filtering steps.\n\n> > @@ -257,15 +257,29 @@ git read-tree || die \"Could not seed the index\"\n> >  # map old->new commit ids for rewriting parents\n> >  mkdir ../map || die \"Could not create map/ directory\"\n> >  \n> > +non_ref_args=$(git rev-parse --no-revs --sq \"$@\")\n> > +dashdash=--\n> > +for arg in \"$non_ref_args\"; do\n> \n> At this point $non_ref_args might contain one or more IFS-separatable\n> words, but if you say \"$non_ref_args\" here, this loop will be entered\n> exactly once. But even if you drop the dquotes, the --sq quoting that you\n> requested from rev-parse bought you nothing.\n\nHrm.  Ok, so the \"..\" were clearly in mistake, but why could I remove\nthe --sq?  Doesn't the shell expand the arguments provided by\n$non_ref_args if I use it without quotes nor --sq, so that it might\naccidentally expand paths or such?\n\n> > +\tif test arg = --; then\n> \n> Did you mean $arg here? Even then this test will succeed only if\n> $non_ref_args contains exactly one word and that word is '--'. Is that\n> what you mean?\n\nNo, it should find a -- argument to see if we need to supply our own\nbefore the $filter_subdir.\n\n> This looks so convoluted; there must be a simpler way to achieve your goal.\n\nI'll try with more 'case's later...  maybe I can at least avoid the\neval.\n\nThanks for your comments!\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"125688","messageId":"4AE0187C.4040608@viscovery.net","threadId":"21313","inReplyTo":"200910221005.11813.trast@student.ethz.ch","subject":"Re: [PATCH v2 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-10-22T08:31:56Z","receivedAt":"2009-10-22T08:31:56Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Thomas Rast schrieb:\n> Well, I just observed while writing the patch that you cannot say\n> \n>   git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n\nPlease include this in the commit message.\n\n> Johannes Sixt wrote:\n>> Thomas Rast schrieb:\n>>> @@ -257,15 +257,29 @@ git read-tree || die \"Could not seed the index\"\n>>>  # map old->new commit ids for rewriting parents\n>>>  mkdir ../map || die \"Could not create map/ directory\"\n>>>  \n>>> +non_ref_args=$(git rev-parse --no-revs --sq \"$@\")\n>>> +dashdash=--\n>>> +for arg in \"$non_ref_args\"; do\n>> At this point $non_ref_args might contain one or more IFS-separatable\n>> words, but if you say \"$non_ref_args\" here, this loop will be entered\n>> exactly once. But even if you drop the dquotes, the --sq quoting that you\n>> requested from rev-parse bought you nothing.\n> \n> Hrm.  Ok, so the \"..\" were clearly in mistake, but why could I remove\n> the --sq?  Doesn't the shell expand the arguments provided by\n> $non_ref_args if I use it without quotes nor --sq, so that it might\n> accidentally expand paths or such?\n\nWhen the shell expands $variable (outside quotes), it does not apply\nquotes anymore, but only word-splits using $IFS. In your code, the words\nwould contain literal single-quotes, and paths with spaces would still be\nsplit into words.\n\nWouldn't it be sufficient to just check whether any non-rev arguments are\npresent, and to suppress '--' if there are, like:\n\ndashdash=\ntest -z \"$(git rev-parse --no-revs \"$@\")\" && dashdash=--\n\nOK, this still leaves you with the problem that you want to separate\nnon-rev arguments from rev arguments. Right?\n\nFor this I suggest that you extract revs into a regular variable (because\nthe SHA1s can be word-split in a predictable way), and that you leave the\nnon-rev arguments in $@:\n\nrevs=$(git rev-parse --revs \"$@\")\t# don't know if this works\neval set -- \"$(git rev-parse --no-revs --sq \"$@\")\"\t# dquotes?\n\nor so... This way you 'eval' should not be needed in later code.\n\n-- Hannes\n"},{"id":"126186","messageId":"6e01558f719f4bfcd12f3c6dc5657790e86c874d.1256770377.git.trast@student.ethz.ch","threadId":"21313","inReplyTo":"4AE0187C.4040608@viscovery.net","subject":"[PATCH v3 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-10-28T22:59:16Z","receivedAt":"2009-10-28T22:59:16Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Handling $filter_subdir in the usual way requires a separate case at\nevery use, because the variable is empty when unused.\n\nFurthermore, the case for --subdirectory-filter supplies its own --,\nso the user cannot provide one himself, so the following was\nimpossible:\n\n  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n\nTo keep the argument handling sane, we filter $@ to contain only the\nnon-revision arguments, and store all revisions in $ref_args.  The\n$ref_args are easy to handle since only the SHA1s are needed; the\nactual branch names have already been stored in $tempdir/heads at this\npoint.\n\nAn extra separating -- is only required if the user did not provide\nany non-revision arguments, as the latter disambiguate the\n$filter_subdir following after them (or fail earlier because they are\nambiguous themselves).\n\nThanks to Johannes Sixt for suggesting this solution.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nJohannes Sixt wrote:\n> When the shell expands $variable (outside quotes), it does not apply\n> quotes anymore, but only word-splits using $IFS. In your code, the words\n> would contain literal single-quotes, and paths with spaces would still be\n> split into words.\n\nIf there's a good reason for these weird rules, I'm still missing\nit...\n\nBut your suggestion works very nicely.\n\n git-filter-branch.sh |   21 ++++++++++++++-------\n 1 files changed, 14 insertions(+), 7 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex a480d6f..da23b99 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -257,15 +257,23 @@ git read-tree || die \"Could not seed the index\"\n # map old->new commit ids for rewriting parents\n mkdir ../map || die \"Could not create map/ directory\"\n \n+dashdash=\n+test -z \"$(git rev-parse --no-revs \"$@\")\" && dashdash=--\n+ref_args=$(git rev-parse --revs-only \"$@\")\n+\n case \"$filter_subdir\" in\n \"\")\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\"\n+\teval set -- \"$(git rev-parse --sq --no-revs \"$@\")\"\n \t;;\n *)\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\" -- \"$filter_subdir\"\n-esac > ../revs || die \"Could not get the commits\"\n+\teval set -- \"$(git rev-parse --sq --no-revs \"$@\")\" \\\n+\t    $dashdash \"$filter_subdir\"\n+\t;;\n+esac\n+\n+git rev-list --reverse --topo-order --default HEAD \\\n+\t--parents --simplify-merges $ref_args \"$@\" \\\n+\t> ../revs || die \"Could not get the commits\"\n commits=$(wc -l <../revs | tr -d \" \")\n \n test $commits -eq 0 && die \"Found nothing to rewrite\"\n@@ -356,8 +364,7 @@ then\n \tdo\n \t\tsha1=$(git rev-parse \"$ref\"^0)\n \t\ttest -f \"$workdir\"/../map/$sha1 && continue\n-\t\tancestor=$(git rev-list --simplify-merges -1 \\\n-\t\t\t\t$ref -- \"$filter_subdir\")\n+\t\tancestor=$(git rev-list --simplify-merges -1 \"$ref\" \"$@\")\n \t\ttest \"$ancestor\" && echo $(map $ancestor) >> \"$workdir\"/../map/$sha1\n \tdone < \"$tempdir\"/heads\n fi\n-- \n1.6.5.1.161.g3b9c0\n"},{"id":"126187","messageId":"a11809cee976bb42102dbd9b2afb06b9e5b587bf.1256770377.git.trast@student.ethz.ch","threadId":"21313","inReplyTo":"6e01558f719f4bfcd12f3c6dc5657790e86c874d.1256770377.git.trast@student.ethz.ch","subject":"[PATCH v3 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-10-28T22:59:17Z","receivedAt":"2009-10-28T22:59:17Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Since a0e4639 (filter-branch: fix ref rewriting with\n--subdirectory-filter, 2008-08-12) git-filter-branch has done\nnearest-ancestor rewriting when using a --subdirectory-filter.\n\nHowever, that rewriting strategy is also a useful building block in\nother tasks.  For example, if you want to split out a subset of files\nfrom your history, you would typically call\n\n  git filter-branch -- <refs> -- <files>\n\nBut this fails for all refs that do not point directly to a commit\nthat affects <files>, because their referenced commit will not be\nrewritten and the ref remains untouched.\n\nThe code was already there for the --subdirectory-filter case, so just\nintroduce an option that enables it independently.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nSame as v2.\n\n Documentation/git-filter-branch.txt |   13 ++++++++++++-\n git-filter-branch.sh                |    9 ++++++++-\n t/t7003-filter-branch.sh            |   18 ++++++++++++++++++\n 3 files changed, 38 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt\nindex 2b40bab..394a77a 100644\n--- a/Documentation/git-filter-branch.txt\n+++ b/Documentation/git-filter-branch.txt\n@@ -159,7 +159,18 @@ to other tags will be rewritten to point to the underlying commit.\n --subdirectory-filter <directory>::\n \tOnly look at the history which touches the given subdirectory.\n \tThe result will contain that directory (and only that) as its\n-\tproject root.\n+\tproject root.  Implies --remap-to-ancestor.\n+\n+--remap-to-ancestor::\n+\tRewrite refs to the nearest rewritten ancestor instead of\n+\tignoring them.\n++\n+Normally, positive refs on the command line are only changed if the\n+commit they point to was rewritten.  However, you can limit the extent\n+of this rewriting by using linkgit:rev-list[1] arguments, e.g., path\n+limiters.  Refs pointing to such excluded commits would then normally\n+be ignored.  With this option, they are instead rewritten to point at\n+the nearest ancestor that was not excluded.\n \n --prune-empty::\n \tSome kind of filters will generate empty commits, that left the tree\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex da23b99..ad2bc6f 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -125,6 +125,7 @@ filter_subdir=\n orig_namespace=refs/original/\n force=\n prune_empty=\n+remap_to_ancestor=\n while :\n do\n \tcase \"$1\" in\n@@ -137,6 +138,11 @@ do\n \t\tforce=t\n \t\tcontinue\n \t\t;;\n+\t--remap-to-ancestor)\n+\t\tshift\n+\t\tremap_to_ancestor=t\n+\t\tcontinue\n+\t\t;;\n \t--prune-empty)\n \t\tshift\n \t\tprune_empty=t\n@@ -182,6 +188,7 @@ do\n \t\t;;\n \t--subdirectory-filter)\n \t\tfilter_subdir=\"$OPTARG\"\n+\t\tremap_to_ancestor=t\n \t\t;;\n \t--original)\n \t\torig_namespace=$(expr \"$OPTARG/\" : '\\(.*[^/]\\)/*$')/\n@@ -358,7 +365,7 @@ done <../revs\n # revision walker.  Fix it by mapping these heads to the unique nearest\n # ancestor that survived the pruning.\n \n-if test \"$filter_subdir\"\n+if test \"$remap_to_ancestor\" = t\n then\n \twhile read ref\n \tdo\ndiff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh\nindex 329c851..9503875 100755\n--- a/t/t7003-filter-branch.sh\n+++ b/t/t7003-filter-branch.sh\n@@ -288,4 +288,22 @@ test_expect_success 'Prune empty commits' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--remap-to-ancestor with filename filters' '\n+\tgit checkout master &&\n+\tgit reset --hard A &&\n+\ttest_commit add-foo foo 1 &&\n+\tgit branch moved-foo &&\n+\ttest_commit add-bar bar a &&\n+\tgit branch invariant &&\n+\torig_invariant=$(git rev-parse invariant) &&\n+\tgit branch moved-bar &&\n+\ttest_commit change-foo foo 2 &&\n+\tgit filter-branch -f --remap-to-ancestor \\\n+\t\tmoved-foo moved-bar A..master \\\n+\t\t-- -- foo &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse moved-bar) &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse master^) &&\n+\ttest $orig_invariant = $(git rev-parse invariant)\n+'\n+\n test_done\n-- \n1.6.5.1.161.g3b9c0\n"},{"id":"126247","messageId":"4AE945D0.5030403@viscovery.net","threadId":"21313","inReplyTo":"6e01558f719f4bfcd12f3c6dc5657790e86c874d.1256770377.git.trast@student.ethz.ch","subject":"Re: [PATCH v3 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-10-29T07:35:44Z","receivedAt":"2009-10-29T07:35:44Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Thomas Rast schrieb:\n> diff --git a/git-filter-branch.sh b/git-filter-branch.sh\n> index a480d6f..da23b99 100755\n> --- a/git-filter-branch.sh\n> +++ b/git-filter-branch.sh\n> @@ -257,15 +257,23 @@ git read-tree || die \"Could not seed the index\"\n>  # map old->new commit ids for rewriting parents\n>  mkdir ../map || die \"Could not create map/ directory\"\n>  \n> +dashdash=\n> +test -z \"$(git rev-parse --no-revs \"$@\")\" && dashdash=--\n\nHmm, if the user runs\n\n   $ git filter-branch does-not-exist\n\nthen this would be the first call to rev-parse that fails with \"fatal:\nambiguous argument 'does-not-exist': unknown revision or path...\", but\nthis code wouldn't catch the failure. I suggest this instead:\n\n# we need \"--\" only if there are no path arguments in $@\nnonrevs=$(git rev-parse --no-revs \"$@\") || exit\ndashdash=${nonrevs+\"--\"}\n\n(including the comment; you can drop the dquotes in the dashdash\nassignment if you think the result is still readable.)\n\nI was to suggest to move these lines into the case arm below that is the\nonly user of $dashdash. But since this is a good error check of the\nuser-supplied arguments, I now prefer to keep the lines outside the case\nstatement.\n\n> +ref_args=$(git rev-parse --revs-only \"$@\")\n\n\"ref_args\"? Shouldn't it be \"rev_args\"? It's about \"revisions\", not\n\"references\".\n\n>  case \"$filter_subdir\" in\n>  \"\")\n> -\tgit rev-list --reverse --topo-order --default HEAD \\\n> -\t\t--parents --simplify-merges \"$@\"\n> +\teval set -- \"$(git rev-parse --sq --no-revs \"$@\")\"\n>  \t;;\n>  *)\n> -\tgit rev-list --reverse --topo-order --default HEAD \\\n> -\t\t--parents --simplify-merges \"$@\" -- \"$filter_subdir\"\n> -esac > ../revs || die \"Could not get the commits\"\n> +\teval set -- \"$(git rev-parse --sq --no-revs \"$@\")\" \\\n> +\t    $dashdash \"$filter_subdir\"\n\nThis is not correct: $filter_subdir undergoes an extra level of\nevaluation. You must write it like this:\n\n\teval set -- \"$(git rev-parse --sq --no-revs \"$@\" \\\n\t\t$dashdash \"$filter_subdir\")\"\n\n> +\t;;\n> +esac\n> +\n> +git rev-list --reverse --topo-order --default HEAD \\\n> +\t--parents --simplify-merges $ref_args \"$@\" \\\n> +\t> ../revs || die \"Could not get the commits\"\n\nPersonally, I would prefer to write this as\n\ngit rev-list --reverse --topo-order --default HEAD \\\n\t--parents --simplify-merges $ref_args \"$@\" > ../revs ||\n\tdie \"Could not get the commits\"\n\nto avoid one backslash.\n\n> @@ -356,8 +364,7 @@ then\n>  \tdo\n>  \t\tsha1=$(git rev-parse \"$ref\"^0)\n>  \t\ttest -f \"$workdir\"/../map/$sha1 && continue\n> -\t\tancestor=$(git rev-list --simplify-merges -1 \\\n> -\t\t\t\t$ref -- \"$filter_subdir\")\n> +\t\tancestor=$(git rev-list --simplify-merges -1 \"$ref\" \"$@\")\n\nYou added dquotes around $ref: while not absolutely necessary, I agree\nwith this change.\n\n>  \t\ttest \"$ancestor\" && echo $(map $ancestor) >> \"$workdir\"/../map/$sha1\n>  \tdone < \"$tempdir\"/heads\n>  fi\n\n-- Hannes\n"},{"id":"126249","messageId":"4AE94687.3070009@viscovery.net","threadId":"21313","inReplyTo":"a11809cee976bb42102dbd9b2afb06b9e5b587bf.1256770377.git.trast@student.ethz.ch","subject":"Re: [PATCH v3 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-10-29T07:38:47Z","receivedAt":"2009-10-29T07:38:47Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Thomas Rast schrieb:\n> @@ -358,7 +365,7 @@ done <../revs\n>  # revision walker.  Fix it by mapping these heads to the unique nearest\n>  # ancestor that survived the pruning.\n>  \n> -if test \"$filter_subdir\"\n> +if test \"$remap_to_ancestor\" = t\n>  then\n\nThe comment whose last lines are in the context of this hunk talks about\n\"subdirectory filter\". You may want to revise it.\n\n-- Hannes\n"},{"id":"127274","messageId":"0280836a32983c848bbb0e3b441be256d3c8f4fa.1257885121.git.trast@student.ethz.ch","threadId":"21313","inReplyTo":"4AE945D0.5030403@viscovery.net","subject":"[PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-11-10T21:04:50Z","receivedAt":"2009-11-10T21:04:50Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Handling $filter_subdir in the usual way requires a separate case at\nevery use, because the variable is empty when unused.\n\nFurthermore, the case for --subdirectory-filter supplies its own --,\nso the user cannot provide one himself, so the following was\nimpossible:\n\n  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n\nTo keep the argument handling sane, we filter $@ to contain only the\nnon-revision arguments, and store all revisions in $ref_args.  The\n$ref_args are easy to handle since only the SHA1s are needed; the\nactual branch names have already been stored in $tempdir/heads at this\npoint.\n\nAn extra separating -- is only required if the user did not provide\nany non-revision arguments, as the latter disambiguate the\n$filter_subdir following after them (or fail earlier because they are\nambiguous themselves).\n\nThanks to Johannes Sixt for suggesting this solution.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nThanks once again for your reviews.  It's been a while since I last\nlooked into this, but after some staring, I think you're right on all\ncounts.\n\nJohannes Sixt wrote:\n> # we need \"--\" only if there are no path arguments in $@\n> nonrevs=$(git rev-parse --no-revs \"$@\") || exit\n> dashdash=${nonrevs+\"--\"}\n> \n> (including the comment; you can drop the dquotes in the dashdash\n> assignment if you think the result is still readable.)\n\nOk.  I was briefly scared that this was bash-specific syntax, but dash\nseems happy so I'll trust your advice.\n\n> This is not correct: $filter_subdir undergoes an extra level of\n> evaluation. You must write it like this:\n> \n> \teval set -- \"$(git rev-parse --sq --no-revs \"$@\" \\\n> \t\t$dashdash \"$filter_subdir\")\"\n\nHopefully I finally understand what's going on here.  The quoting\nrules make my head spin.\n\n> > -\t\tancestor=$(git rev-list --simplify-merges -1 \\\n> > -\t\t\t\t$ref -- \"$filter_subdir\")\n> > +\t\tancestor=$(git rev-list --simplify-merges -1 \"$ref\" \"$@\")\n> \n> You added dquotes around $ref: while not absolutely necessary, I agree\n> with this change.\n\nIt's kind of a sneak fix, but I broke this back in the ancestor\nrewriting patch...  Luckily the refname sanity rules are designed to\nprevent this from causing any harm.\n\n\n git-filter-branch.sh |   22 +++++++++++++++-------\n 1 files changed, 15 insertions(+), 7 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex a480d6f..96b2182 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -257,15 +257,24 @@ git read-tree || die \"Could not seed the index\"\n # map old->new commit ids for rewriting parents\n mkdir ../map || die \"Could not create map/ directory\"\n \n+# we need \"--\" only if there are no path arguments in $@\n+nonrevs=$(git rev-parse --no-revs \"$@\") || exit\n+dashdash=${nonrevs+\"--\"}\n+rev_args=$(git rev-parse --revs-only \"$@\")\n+\n case \"$filter_subdir\" in\n \"\")\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\"\n+\teval set -- \"$(git rev-parse --sq --no-revs \"$@\")\"\n \t;;\n *)\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\" -- \"$filter_subdir\"\n-esac > ../revs || die \"Could not get the commits\"\n+\teval set -- \"$(git rev-parse --sq --no-revs \"$@\" $dashdash \\\n+\t\t\"$filter_subdir\")\"\n+\t;;\n+esac\n+\n+git rev-list --reverse --topo-order --default HEAD \\\n+\t--parents --simplify-merges $rev_args \"$@\" > ../revs ||\n+\tdie \"Could not get the commits\"\n commits=$(wc -l <../revs | tr -d \" \")\n \n test $commits -eq 0 && die \"Found nothing to rewrite\"\n@@ -356,8 +365,7 @@ then\n \tdo\n \t\tsha1=$(git rev-parse \"$ref\"^0)\n \t\ttest -f \"$workdir\"/../map/$sha1 && continue\n-\t\tancestor=$(git rev-list --simplify-merges -1 \\\n-\t\t\t\t$ref -- \"$filter_subdir\")\n+\t\tancestor=$(git rev-list --simplify-merges -1 \"$ref\" \"$@\")\n \t\ttest \"$ancestor\" && echo $(map $ancestor) >> \"$workdir\"/../map/$sha1\n \tdone < \"$tempdir\"/heads\n fi\n-- \n1.6.5.2.365.ge9237\n"},{"id":"127275","messageId":"89074b84e9b4f8c0c064cb39693d936f2e931786.1257885121.git.trast@student.ethz.ch","threadId":"21313","inReplyTo":"0280836a32983c848bbb0e3b441be256d3c8f4fa.1257885121.git.trast@student.ethz.ch","subject":"[PATCH v4 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-11-10T21:04:51Z","receivedAt":"2009-11-10T21:04:51Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Since a0e4639 (filter-branch: fix ref rewriting with\n--subdirectory-filter, 2008-08-12) git-filter-branch has done\nnearest-ancestor rewriting when using a --subdirectory-filter.\n\nHowever, that rewriting strategy is also a useful building block in\nother tasks.  For example, if you want to split out a subset of files\nfrom your history, you would typically call\n\n  git filter-branch -- <refs> -- <files>\n\nBut this fails for all refs that do not point directly to a commit\nthat affects <files>, because their referenced commit will not be\nrewritten and the ref remains untouched.\n\nThe code was already there for the --subdirectory-filter case, so just\nintroduce an option that enables it independently.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nCompared to v3 this only changes the comment, as suggested by Johannes\nSixt.\n\n\n Documentation/git-filter-branch.txt |   13 ++++++++++++-\n git-filter-branch.sh                |   18 +++++++++++++-----\n t/t7003-filter-branch.sh            |   18 ++++++++++++++++++\n 3 files changed, 43 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt\nindex 2b40bab..394a77a 100644\n--- a/Documentation/git-filter-branch.txt\n+++ b/Documentation/git-filter-branch.txt\n@@ -159,7 +159,18 @@ to other tags will be rewritten to point to the underlying commit.\n --subdirectory-filter <directory>::\n \tOnly look at the history which touches the given subdirectory.\n \tThe result will contain that directory (and only that) as its\n-\tproject root.\n+\tproject root.  Implies --remap-to-ancestor.\n+\n+--remap-to-ancestor::\n+\tRewrite refs to the nearest rewritten ancestor instead of\n+\tignoring them.\n++\n+Normally, positive refs on the command line are only changed if the\n+commit they point to was rewritten.  However, you can limit the extent\n+of this rewriting by using linkgit:rev-list[1] arguments, e.g., path\n+limiters.  Refs pointing to such excluded commits would then normally\n+be ignored.  With this option, they are instead rewritten to point at\n+the nearest ancestor that was not excluded.\n \n --prune-empty::\n \tSome kind of filters will generate empty commits, that left the tree\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 96b2182..a5a0352 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -125,6 +125,7 @@ filter_subdir=\n orig_namespace=refs/original/\n force=\n prune_empty=\n+remap_to_ancestor=\n while :\n do\n \tcase \"$1\" in\n@@ -137,6 +138,11 @@ do\n \t\tforce=t\n \t\tcontinue\n \t\t;;\n+\t--remap-to-ancestor)\n+\t\tshift\n+\t\tremap_to_ancestor=t\n+\t\tcontinue\n+\t\t;;\n \t--prune-empty)\n \t\tshift\n \t\tprune_empty=t\n@@ -182,6 +188,7 @@ do\n \t\t;;\n \t--subdirectory-filter)\n \t\tfilter_subdir=\"$OPTARG\"\n+\t\tremap_to_ancestor=t\n \t\t;;\n \t--original)\n \t\torig_namespace=$(expr \"$OPTARG/\" : '\\(.*[^/]\\)/*$')/\n@@ -354,12 +361,13 @@ while read commit parents; do\n \t\t\tdie \"could not write rewritten commit\"\n done <../revs\n \n-# In case of a subdirectory filter, it is possible that a specified head\n-# is not in the set of rewritten commits, because it was pruned by the\n-# revision walker.  Fix it by mapping these heads to the unique nearest\n-# ancestor that survived the pruning.\n+# If we are filtering for paths, as in the case of a subdirectory\n+# filter, it is possible that a specified head is not in the set of\n+# rewritten commits, because it was pruned by the revision walker.\n+# Ancestor remapping fixes this by mapping these heads to the unique\n+# nearest ancestor that survived the pruning.\n \n-if test \"$filter_subdir\"\n+if test \"$remap_to_ancestor\" = t\n then\n \twhile read ref\n \tdo\ndiff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh\nindex 329c851..9503875 100755\n--- a/t/t7003-filter-branch.sh\n+++ b/t/t7003-filter-branch.sh\n@@ -288,4 +288,22 @@ test_expect_success 'Prune empty commits' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--remap-to-ancestor with filename filters' '\n+\tgit checkout master &&\n+\tgit reset --hard A &&\n+\ttest_commit add-foo foo 1 &&\n+\tgit branch moved-foo &&\n+\ttest_commit add-bar bar a &&\n+\tgit branch invariant &&\n+\torig_invariant=$(git rev-parse invariant) &&\n+\tgit branch moved-bar &&\n+\ttest_commit change-foo foo 2 &&\n+\tgit filter-branch -f --remap-to-ancestor \\\n+\t\tmoved-foo moved-bar A..master \\\n+\t\t-- -- foo &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse moved-bar) &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse master^) &&\n+\ttest $orig_invariant = $(git rev-parse invariant)\n+'\n+\n test_done\n-- \n1.6.5.2.365.ge9237\n"},{"id":"127296","messageId":"4AFA7624.5040400@viscovery.net","threadId":"21313","inReplyTo":"0280836a32983c848bbb0e3b441be256d3c8f4fa.1257885121.git.trast@student.ethz.ch","subject":"Re: [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-11-11T08:30:28Z","receivedAt":"2009-11-11T08:30:28Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Thomas Rast schrieb:\n> Johannes Sixt wrote:\n>> # we need \"--\" only if there are no path arguments in $@\n>> nonrevs=$(git rev-parse --no-revs \"$@\") || exit\n>> dashdash=${nonrevs+\"--\"}\n>>\n>> (including the comment; you can drop the dquotes in the dashdash\n>> assignment if you think the result is still readable.)\n> \n> Ok.  I was briefly scared that this was bash-specific syntax, but dash\n> seems happy so I'll trust your advice.\n\nYou shouldn't. I'm wrong ;-)\n\nIn the snippet above, dashdash will always be set to \"--\" because a mere\n'+' in the variable expansion only tests whether the variable ('nonrevs')\nis unset, but it is always set. Even ${nonrevs:+\"--\"} is wrong, and your\nearlier 'test -z' invocation was the correct way to set dashdash.\n\nBut...\n\nI did some testing, and now I have to wonder about the use-case that you\npresent in the commit message:\n\n> Furthermore, the case for --subdirectory-filter supplies its own --,\n> so the user cannot provide one himself, so the following was\n> impossible:\n>\n>   git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n\nIf you try in git.git itself:\n\n  $ git rev-list --simplify-merges --all -- \\\n\tDocumentation/git-commit.txt | wc -l\n  84\n  $ git rev-list --simplify-merges --all -- \\\n\tDocumentation/git-commit.txt Documentation | wc -l\n  4624\n\nI thought that the intention to give an extra path argument is to reduce\nthe number of commits that remain in the rewritten history. But by giving\n--subdirectory-filter, the path filter actually loosened, and many more\ncommits are rewritten.\n\nSince your intention to write this patch is actually to implement\n--remap-to-ancestor, I suggest that we defer the question whether the\nabove use-case makes sense, and only rewrite this particular paragraph in\nthe commit message to point out the real bug:\n\n-----\nFurthermore, --subdirectory-filter supplies its own '--', and if the user\nprovided one himself, such as in\n\n  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n\nan extra '--' was used as path filter in the call to git-rev-list that\ndetermines the commits that shall be rewritten.\n-----\n\nI'll submit a replacement patch.\n\n-- Hannes\n"},{"id":"127301","messageId":"4AFA7B9A.4090005@viscovery.net","threadId":"21313","inReplyTo":"4AFA7624.5040400@viscovery.net","subject":"[PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-11-11T08:53:46Z","receivedAt":"2009-11-11T08:53:46Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"From: Thomas Rast <trast@student.ethz.ch>\n\nHandling $filter_subdir in the usual way requires a separate case at\nevery use, because the variable is empty when unused.\n\nFurthermore, --subdirectory-filter supplies its own '--', and if the user\nprovided one himself, such as in\n\n  git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n\n\tan extra '--' was used as path filter in the call to git-rev-list that\ndetermines the commits that shall be rewritten.\n\nTo keep the argument handling sane, we filter $@ to contain only the\nnon-revision arguments, and store all revisions in $ref_args.  The\n$ref_args are easy to handle since only the SHA1s are needed; the\nactual branch names have already been stored in $tempdir/heads at this\npoint.\n\nAn extra separating -- is only required if the user did not provide\nany non-revision arguments, as the latter disambiguate the\n$filter_subdir following after them (or fail earlier because they are\nambiguous themselves).\n\nThanks to Johannes Sixt for suggesting this solution.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\nJohannes Sixt schrieb:\n> I'll submit a replacement patch.\n\nHere it is. The interdiff to your version is merely\n\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -266,7 +266,7 @@\n\n # we need \"--\" only if there are no path arguments in $@\n nonrevs=$(git rev-parse --no-revs \"$@\") || exit\n-dashdash=${nonrevs+\"--\"}\n+test -z \"$nonrevs\" && dashdash=-- || dashdash=\n rev_args=$(git rev-parse --revs-only \"$@\")\n\n case \"$filter_subdir\" in\n\nand I changed the commit message in the way I announced it.\n\n-- Hannes\n\n git-filter-branch.sh |   22 +++++++++++++++-------\n 1 files changed, 15 insertions(+), 7 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex a480d6f..ed3db7d 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -257,15 +257,24 @@ git read-tree || die \"Could not seed the index\"\n # map old->new commit ids for rewriting parents\n mkdir ../map || die \"Could not create map/ directory\"\n\n+# we need \"--\" only if there are no path arguments in $@\n+nonrevs=$(git rev-parse --no-revs \"$@\") || exit\n+test -z \"$nonrevs\" && dashdash=-- || dashdash=\n+rev_args=$(git rev-parse --revs-only \"$@\")\n+\n case \"$filter_subdir\" in\n \"\")\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\"\n+\teval set -- \"$(git rev-parse --sq --no-revs \"$@\")\"\n \t;;\n *)\n-\tgit rev-list --reverse --topo-order --default HEAD \\\n-\t\t--parents --simplify-merges \"$@\" -- \"$filter_subdir\"\n-esac > ../revs || die \"Could not get the commits\"\n+\teval set -- \"$(git rev-parse --sq --no-revs \"$@\" $dashdash \\\n+\t\t\"$filter_subdir\")\"\n+\t;;\n+esac\n+\n+git rev-list --reverse --topo-order --default HEAD \\\n+\t--parents --simplify-merges $rev_args \"$@\" > ../revs ||\n+\tdie \"Could not get the commits\"\n commits=$(wc -l <../revs | tr -d \" \")\n\n test $commits -eq 0 && die \"Found nothing to rewrite\"\n@@ -356,8 +365,7 @@ then\n \tdo\n \t\tsha1=$(git rev-parse \"$ref\"^0)\n \t\ttest -f \"$workdir\"/../map/$sha1 && continue\n-\t\tancestor=$(git rev-list --simplify-merges -1 \\\n-\t\t\t\t$ref -- \"$filter_subdir\")\n+\t\tancestor=$(git rev-list --simplify-merges -1 \"$ref\" \"$@\")\n \t\ttest \"$ancestor\" && echo $(map $ancestor) >> \"$workdir\"/../map/$sha1\n \tdone < \"$tempdir\"/heads\n fi\n-- \n1.6.5.rc2.47.g49402\n"},{"id":"127302","messageId":"4AFA7C1E.1050606@viscovery.net","threadId":"21313","inReplyTo":"4AFA7B9A.4090005@viscovery.net","subject":"[PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-11-11T08:55:58Z","receivedAt":"2009-11-11T08:55:58Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"From: Thomas Rast <trast@student.ethz.ch>\nDate: Tue, 10 Nov 2009 22:04:51 +0100\n\nSince a0e4639 (filter-branch: fix ref rewriting with\n--subdirectory-filter, 2008-08-12) git-filter-branch has done\nnearest-ancestor rewriting when using a --subdirectory-filter.\n\nHowever, that rewriting strategy is also a useful building block in\nother tasks.  For example, if you want to split out a subset of files\nfrom your history, you would typically call\n\n  git filter-branch -- <refs> -- <files>\n\nBut this fails for all refs that do not point directly to a commit\nthat affects <files>, because their referenced commit will not be\nrewritten and the ref remains untouched.\n\nThe code was already there for the --subdirectory-filter case, so just\nintroduce an option that enables it independently.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n\nOnly resent for Junio's convenience. It is identical to your v4, but\nwith my SOB added.\n\n-- Hannes\n\n Documentation/git-filter-branch.txt |   13 ++++++++++++-\n git-filter-branch.sh                |   18 +++++++++++++-----\n t/t7003-filter-branch.sh            |   18 ++++++++++++++++++\n 3 files changed, 43 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt\nindex 2b40bab..394a77a 100644\n--- a/Documentation/git-filter-branch.txt\n+++ b/Documentation/git-filter-branch.txt\n@@ -159,7 +159,18 @@ to other tags will be rewritten to point to the underlying commit.\n --subdirectory-filter <directory>::\n \tOnly look at the history which touches the given subdirectory.\n \tThe result will contain that directory (and only that) as its\n-\tproject root.\n+\tproject root.  Implies --remap-to-ancestor.\n+\n+--remap-to-ancestor::\n+\tRewrite refs to the nearest rewritten ancestor instead of\n+\tignoring them.\n++\n+Normally, positive refs on the command line are only changed if the\n+commit they point to was rewritten.  However, you can limit the extent\n+of this rewriting by using linkgit:rev-list[1] arguments, e.g., path\n+limiters.  Refs pointing to such excluded commits would then normally\n+be ignored.  With this option, they are instead rewritten to point at\n+the nearest ancestor that was not excluded.\n\n --prune-empty::\n \tSome kind of filters will generate empty commits, that left the tree\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex ed3db7d..6b8b6a4 100755\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -125,6 +125,7 @@ filter_subdir=\n orig_namespace=refs/original/\n force=\n prune_empty=\n+remap_to_ancestor=\n while :\n do\n \tcase \"$1\" in\n@@ -137,6 +138,11 @@ do\n \t\tforce=t\n \t\tcontinue\n \t\t;;\n+\t--remap-to-ancestor)\n+\t\tshift\n+\t\tremap_to_ancestor=t\n+\t\tcontinue\n+\t\t;;\n \t--prune-empty)\n \t\tshift\n \t\tprune_empty=t\n@@ -182,6 +188,7 @@ do\n \t\t;;\n \t--subdirectory-filter)\n \t\tfilter_subdir=\"$OPTARG\"\n+\t\tremap_to_ancestor=t\n \t\t;;\n \t--original)\n \t\torig_namespace=$(expr \"$OPTARG/\" : '\\(.*[^/]\\)/*$')/\n@@ -354,12 +361,13 @@ while read commit parents; do\n \t\t\tdie \"could not write rewritten commit\"\n done <../revs\n\n-# In case of a subdirectory filter, it is possible that a specified head\n-# is not in the set of rewritten commits, because it was pruned by the\n-# revision walker.  Fix it by mapping these heads to the unique nearest\n-# ancestor that survived the pruning.\n+# If we are filtering for paths, as in the case of a subdirectory\n+# filter, it is possible that a specified head is not in the set of\n+# rewritten commits, because it was pruned by the revision walker.\n+# Ancestor remapping fixes this by mapping these heads to the unique\n+# nearest ancestor that survived the pruning.\n\n-if test \"$filter_subdir\"\n+if test \"$remap_to_ancestor\" = t\n then\n \twhile read ref\n \tdo\ndiff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh\nindex 329c851..9503875 100755\n--- a/t/t7003-filter-branch.sh\n+++ b/t/t7003-filter-branch.sh\n@@ -288,4 +288,22 @@ test_expect_success 'Prune empty commits' '\n \ttest_cmp expect actual\n '\n\n+test_expect_success '--remap-to-ancestor with filename filters' '\n+\tgit checkout master &&\n+\tgit reset --hard A &&\n+\ttest_commit add-foo foo 1 &&\n+\tgit branch moved-foo &&\n+\ttest_commit add-bar bar a &&\n+\tgit branch invariant &&\n+\torig_invariant=$(git rev-parse invariant) &&\n+\tgit branch moved-bar &&\n+\ttest_commit change-foo foo 2 &&\n+\tgit filter-branch -f --remap-to-ancestor \\\n+\t\tmoved-foo moved-bar A..master \\\n+\t\t-- -- foo &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse moved-bar) &&\n+\ttest $(git rev-parse moved-foo) = $(git rev-parse master^) &&\n+\ttest $orig_invariant = $(git rev-parse invariant)\n+'\n+\n test_done\n-- \n1.6.5.rc2.47.g49402\n"},{"id":"127303","messageId":"4AFA7CC3.6020500@viscovery.net","threadId":"21313","inReplyTo":"4AFA7B9A.4090005@viscovery.net","subject":"Re: [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-11-11T08:58:43Z","receivedAt":"2009-11-11T08:58:43Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johannes Sixt schrieb:\n> --- a/git-filter-branch.sh\n> +++ b/git-filter-branch.sh\n> @@ -266,7 +266,7 @@\n> \n>  # we need \"--\" only if there are no path arguments in $@\n>  nonrevs=$(git rev-parse --no-revs \"$@\") || exit\n> -dashdash=${nonrevs+\"--\"}\n> +test -z \"$nonrevs\" && dashdash=-- || dashdash=\n>  rev_args=$(git rev-parse --revs-only \"$@\")\n> \n>  case \"$filter_subdir\" in\n\nArrgh! I should have indented these lines so that they\ndo not count as patch text.\n\nSorry.\n\n-- Hannes\n"},{"id":"127314","messageId":"200911111124.52340.trast@student.ethz.ch","threadId":"21313","inReplyTo":"4AFA7B9A.4090005@viscovery.net","subject":"Re: [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-11-11T10:24:49Z","receivedAt":"2009-11-11T10:24:49Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Johannes Sixt wrote in the other reply:\n> I thought that the intention to give an extra path argument is to reduce\n> the number of commits that remain in the rewritten history. But by giving\n> --subdirectory-filter, the path filter actually loosened, and many more\n> commits are rewritten.\n\nRight, I had a thinko there, the path filter adds up as an \"or\", so\nfiltering for paths outside the subdir loosens it (and filtering for\nmore paths inside doesn't make a difference).\n\n> Since your intention to write this patch is actually to implement\n> --remap-to-ancestor, I suggest that we defer the question whether the\n> above use-case makes sense, and only rewrite this particular paragraph in\n> the commit message to point out the real bug:\n\nAgreed.\n\nJohannes Sixt wrote:\n> Furthermore, --subdirectory-filter supplies its own '--', and if the user\n> provided one himself, such as in\n> \n>   git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n> \n> \tan extra '--' was used as path filter in the call to git-rev-list that\n> determines the commits that shall be rewritten.\n\nThere's some stray space here that should probably also be removed.\n\n> Here it is. The interdiff to your version is merely\n[...]\n>  # we need \"--\" only if there are no path arguments in $@\n>  nonrevs=$(git rev-parse --no-revs \"$@\") || exit\n> -dashdash=${nonrevs+\"--\"}\n> +test -z \"$nonrevs\" && dashdash=-- || dashdash=\n\nAck.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"127321","messageId":"4AFAA9C3.5080402@viscovery.net","threadId":"21313","inReplyTo":"200911111124.52340.trast@student.ethz.ch","subject":"Re: [PATCH v5 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-11-11T12:10:43Z","receivedAt":"2009-11-11T12:10:43Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Thomas Rast schrieb:\n> Johannes Sixt wrote:\n>> Furthermore, --subdirectory-filter supplies its own '--', and if the user\n>> provided one himself, such as in\n>>\n>>   git filter-branch --subdirectory-filter subdir -- --all -- subdir/file\n>>\n>> \tan extra '--' was used as path filter in the call to git-rev-list that\n>> determines the commits that shall be rewritten.\n> \n> There's some stray space here that should probably also be removed.\n\nOh, right. Junio, you can pick up the 2-patch series from\n\n  git://repo.or.cz/git/mingw/j6t.git filter-branch\n\n-- Hannes\n"},{"id":"127357","messageId":"7v3a4lq6uo.fsf@alter.siamese.dyndns.org","threadId":"21313","inReplyTo":"4AFA7624.5040400@viscovery.net","subject":"Re: [PATCH v4 1/2] filter-branch: stop special-casing $filter_subdir argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-11-11T18:00:47Z","receivedAt":"2009-11-11T18:00:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n> In the snippet above, dashdash will always be set to \"--\" because a mere\n> '+' in the variable expansion only tests whether the variable ('nonrevs')\n> is unset, but it is always set. Even ${nonrevs:+\"--\"} is wrong, and your\n> earlier 'test -z' invocation was the correct way to set dashdash.\n\nI do not mind \"test -z\", so this is just for information, but you could\nuse variable substitution with a colon, i.e. ${nonrevs:+\"--\"}.\n\nIIRC, the colon-form (\"do this if unset or empty\") wasn't understood by\nancient BSDs but these days it is safe to use.\n"},{"id":"127358","messageId":"7vocn8q5v2.fsf@alter.siamese.dyndns.org","threadId":"21313","inReplyTo":"4AFA7C1E.1050606@viscovery.net","subject":"Re: [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-11-11T18:22:09Z","receivedAt":"2009-11-11T18:22:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n> However, that rewriting strategy is also a useful building block in\n> other tasks.  For example, if you want to split out a subset of files\n> from your history, you would typically call\n>\n>   git filter-branch -- <refs> -- <files>\n>\n> But this fails for all refs that do not point directly to a commit\n> that affects <files>, because their referenced commit will not be\n> rewritten and the ref remains untouched.\n>\n> The code was already there for the --subdirectory-filter case, so just\n> introduce an option that enables it independently.\n>\n> Signed-off-by: Thomas Rast <trast@student.ethz.ch>\n> Signed-off-by: Johannes Sixt <j6t@kdbg.org>\n\nUp to this point, nothing mentions the name of the new option.  Please\nwrite your log for a person who needs to write the release notes by\nlooking at \"git shortlog\" output ;-)\n\nI am wondering if this even needs an option to trigger.  Shouldn't you\nwant this behaviour always when you give any pathspec?\n\nWhat are the sane reasons to leave the rewritten ref to point at the old\ncommit, essentially making the rewritten history unreachable?\n"},{"id":"127359","messageId":"200911111936.06332.trast@student.ethz.ch","threadId":"21313","inReplyTo":"7vocn8q5v2.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v5 2/2] filter-branch: nearest-ancestor rewriting outside subdir filter","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-11-11T18:36:04Z","receivedAt":"2009-11-11T18:36:04Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> \n> Up to this point, nothing mentions the name of the new option.  Please\n> write your log for a person who needs to write the release notes by\n> looking at \"git shortlog\" output ;-)\n> \n> I am wondering if this even needs an option to trigger.  Shouldn't you\n> want this behaviour always when you give any pathspec?\n> \n> What are the sane reasons to leave the rewritten ref to point at the old\n> commit, essentially making the rewritten history unreachable?\n\nFear of hysterical raisins, nothing else.  I cannot really see a\nuse-case of the original behaviour, and since it does not change the\nbehaviour in the case of an unfiltered rewrite, it should be safe to\nalways be enabled.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"}]}