git filter-branch --tree-filter with --since return"找不到任何重写"

时间:2014-09-02 03:56:14

标签: git git-filter-branch

我试图在某个日期之后对所有提交执行命令:

git filter-branch -f --tree-filter <command> HEAD -- --since="2014-06-01 13:37" <name-of-branch>

不幸的是,它始终输出Found nothing to rewrite并停止。 --之后的所有内容都应被视为rev-list的选项,以便我尝试:

git rev-list --since="2014-06-01 13:37" <name-of-branch>

自2014-06-01以来,我将获得正确的所有修订版本。

我做错了什么?

1 个答案:

答案 0 :(得分:5)

我复制了一个git repo并使用类似的选项运行filter-branch脚本(只是组成一个不同的--since来选择一个或两个特定分支上的两个),并发现深在脚本中,文档说--之后的参数传递给git rev-list,过滤器分支代码最终传递这些参数,就好像它们是路径说明符一样。这似乎是filter-branch中的一个错误。

特别是:

$ git rev-list --since=2013-01-01 branch
222c4dd303570d096f0346c3cd1dff6ea2c84f83
$ git rev-list branch
222c4dd303570d096f0346c3cd1dff6ea2c84f83
fb45c22c932d16903ae9e4debb8483a58a4e7799
fc85842f31baa62292abc3a539e86d0971caf8d9
2a5aaf8429ad810b25ef49f62bfda302b3193852
630a11ba2516023246e1e3eccf7023e915870489
4b597cf400a040a6bb14329890d65f126be88af2

这表明如果我故意重写branch本身,它应该复制(带过滤)六次提交,但是--since=2013-01-01它应该只复制(带过滤)一次提交。由于我实际上不在分支branch上,我还会将上面的HEAD替换为branch,以消除重写分支HEAD名称意味着什么的问题,同时选择branch指向的转速。

同时,我提供了一个无意义的树过滤器(不做任何更改,但提供了一些输出)。因此,我的filter-branch命令是:

$ git filter-branch -f --tree-filter ls branch -- --since=2013-01-01 branch
Found nothing to rewrite

现在让我们揭露git filter-branch的内部运作方式。为此,我必须暂时将/usr/local/libexec/git-core放在我的$PATH

$ c=/usr/local/libexec/git-core  # so I don't have to retype it
$ PATH=$c:$PATH sh -x $c/git-filter-branch \
>  -f --tree-filter ls branch -- --since=2013-01-01 branch

-x在运行时显示每一行。有一大堆设置,然后输出包括:

+ git rev-parse --no-flags --revs-only --symbolic-full-name --default HEAD branch -- --since=2013-01-01 branch
+ sed -e /^^/d /tmp/t2/.git-rewrite/raw-heads

(这得到&#34;肯定的内容参考重写&#34 ;;尽管有明显的&#34;额外的&#34; --

这部分是正确的
+ test -s /tmp/t2/.git-rewrite/heads

(这确保至少有一个分支名称要重写)

+ pwd
+ GIT_INDEX_FILE=/tmp/t2/.git-rewrite/t/../index
+ export GIT_INDEX_FILE

(这是索引过滤器的更多设置等)

+ mkdir ../map
+ git rev-parse --no-revs branch -- --since=2013-01-01 branch
+ nonrevs='--
--since=2013-01-01
branch'
+ test -z '--
--since=2013-01-01
branch'
+ dashdash=''
+ remap_to_ancestor=t

这将检查要传递给git rev-list的参数,以查找是否存在基于路径的修订限制器。它决定 -- since=...被视为路径规范,因此将$dashdash设置为空,将remap_to_ancestors设置为t(真正)。奇怪的是,$dashdash仅在我们提供--subdirectory-filter时使用,我们没有。此代码看起来很可疑,但本身并不是问题的直接来源。

接下来的一点:

+ git rev-parse --revs-only branch -- --since=2013-01-01 branch

将转录列表写入重写到临时文件(../parse,此处未显示)。在我的情况下,branch222c4dd...本身就是+ git rev-parse --sq --no-revs branch -- --since=2013-01-01 branch + eval set -- \''--'\'' '\''--since=2013-01-01'\'' '\''branch'\'' ' + set -- -- --since=2013-01-01 branch 。这是可以的,但下一步:

git rev-list

这会将参数更新为&#34;只是传递给+ git rev-list --reverse --topo-order --default HEAD --parents --simplify-merges --stdin -- --since=2013-01-01 branch + wc -l + tr -d ' ' + commits=0 + test 0 -eq 0 + die 'Found nothing to rewrite' &#34;的参数,然后:

git rev-list

上面的最后一个--stdin应该产生最后一组提交重写。原始集(来自../parse和临时文件--since=... branch)是正确的,但这已经过--all作为路径说明符(纯粹是限制修订版),而不是其他修订版生成器(可能添加 revs,与git filter-branch --env-filter : -- --all 一样)。

如果您使用手册页中的一些示例,例如(我已将此修改为无操作):

git rev-parse

他们有效,因为--all了解git filter-branch,因此不会传递给最后一个+ git rev-list --reverse --topo-order --default HEAD --parents --simplify-merges --stdin

--all

事实上,parse导致refs进入--stdin文件,这是--since内容,因此这适用于所有可到达的提交。


无论如何,虽然这太长了(因为我没有时间缩短它),但归结为这样一个事实:至少现在,你不能在这里使用git rev-parse限制器。他们可能应该工作,但它需要filter-branch脚本更巧妙地解析参数(可能借助--)。如果那最后一个&#34;设置&#34;没有插入文字rev-list ... --stdin--since=... branch会收到--作为参数,并会做正确的事情。但是,对于实际的路径限制器,应该有--

我不清楚错误是过滤器分支文档是否暗示所有 rev-list选项在这里(当它们不是)时,或者代码我强调的脚本部分应该更加智能,或者可能只是不同(例如,路径限制器可能需要两个 --since参数)。但无论如何,它必须是git中的一个错误,因为文档表明{{1}}可以工作,但事实并非如此。