我复制了一个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
可以工作,而不是。
这看起来像'filter-branch'脚本中的一个bug;它使用两个'--'参数调用'git rev-list',但'git rev-list'只能用一个正确地工作。错误的实际来源对我来说并不清楚,但在git-as-it中,你实际上不能将这些选项传递给'git rev-list'。 – torek 2014-09-02 04:47:12
谢谢@torek - 我感谢您对此进行调查。所以它不是我,它是'git'! :)为什么不用这个信息发布答案,我会接受它。 – ierceg 2014-09-03 12:47:48
我真的没有时间写出正确的答案,但如果你喜欢,我会将评论复制到答案... – torek 2014-09-03 16:55:41