我试图在某个日期之后对所有提交执行命令:
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以来,我将获得正确的所有修订版本。
我做错了什么?
答案 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
,此处未显示)。在我的情况下,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
这会将参数更新为&#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}}可以工作,但事实并非如此。