2014-09-02 61 views
2

我想在某个日期的所有承诺执行命令:git的过滤分支--tree过滤器“没有发现任何改写”

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

这看起来像'filter-branch'脚本中的一个bug;它使用两个'--'参数调用'git rev-list',但'git rev-list'只能用一个正确地工作。错误的实际来源对我来说并不清楚,但在git-as-it中,你实际上不能将这些选项传递给'git rev-list'。 – torek 2014-09-02 04:47:12

+0

谢谢@torek - 我感谢您对此进行调查。所以它不是我,它是'git'! :)为什么不用这个信息发布答案,我会接受它。 – ierceg 2014-09-03 12:47:48

+0

我真的没有时间写出正确的答案,但如果你喜欢,我会将评论复制到答案... – torek 2014-09-03 16:55:41

回答

2

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

特别是:

$ 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上,我还将用branch替换上面的HEAD,以消除重写分支HEAD名称的意义,同时选择指向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 

(此获得的“阳性参改写”的列表;这部分是正确的,尽管看起来“额外” --

+ 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=...被视为一个pathspec,因此这将$dashdash设置为空,并将remap_to_ancestors设置为t(简写为true)。奇怪的是,$dashdash只用于我们提供的--subdirectory-filter,我们没有。这段代码看起来很可疑,但本身并不是问题的直接根源。

下位:

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

写入转速的列表改写到一个临时文件(../parse,这里没有显示)。在我的情况下,这是branch点,这是222c4dd...本身。这是尽可能去确定,但未来:

+ 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”,然后:

+ 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' 

最后git rev-list上面应该产生最后一组提交 - 重写。原载(从--stdin和临时文件../parse)是正确的,但是这已经过去了--since=... branch为路径说明符(纯限制修订版),而不是另外修订发电机(可能添加转速,与--all)。

如果你使用一些从手册页,如例子(我已经修改了这一个是一个空操作):

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文件,该文件是--stdin内容,使该工程对人l可达到提交。


不管怎么说,这是太长了(因为我没有时间缩短),把它归结为一个事实,即,至少现在,你不能在这里使用--since限制器。他们可能应该工作,但它需要过滤器分支脚本更聪明地解析参数(也许在git rev-parse的帮助下)。如果最后一个“set”没有插入文字--,那么rev-list ... --stdin将会收到--since=... branch作为参数,并且会做正确的事情。但对于实际的路径限制器,应该有一个--

我不清楚这个错误是否是过滤器分支文档建议全部 rev-list选项在这里是允许的(当它们不是)时,或者脚本部分的代码I'已经强调应该更聪明,或者可能只是不同(例如,路径限制器可能需要参数两个--参数)。但无论如何,它必须是git中的一个bug,因为文档建议--since可以工作,而不是。

+0

谢谢你*非常*彻底的答案! – ierceg 2014-09-05 22:04:56