ier*_*ceg 4 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年6月1日起,我将获得所有修订版本的正确集合。
我究竟做错了什么?
我复制了一个git repo并filter-branch使用相似的选项运行了脚本(只是组成一个差异--since以从特定分支中选择一个或两个版本),并在脚本的深处发现文档说明--传递了以下参数到git rev-list,过滤分支代码结束传递这些参数,就好像它们是路径说明符一样。这似乎是筛选器分支中的错误。
特别是:
$ git rev-list --since=2013-01-01 branch
222c4dd303570d096f0346c3cd1dff6ea2c84f83
$ git rev-list branch
222c4dd303570d096f0346c3cd1dff6ea2c84f83
fb45c22c932d16903ae9e4debb8483a58a4e7799
fc85842f31baa62292abc3a539e86d0971caf8d9
2a5aaf8429ad810b25ef49f62bfda302b3193852
630a11ba2516023246e1e3eccf7023e915870489
4b597cf400a040a6bb14329890d65f126be88af2
Run Code Online (Sandbox Code Playgroud)
这表明,如果我故意重写branch自身,它应该复制(带有过滤)六个提交,但是--since=2013-01-01应该只复制(带有过滤)一个提交。由于我实际上不在分支上,因此在选择by指向的revs时,branch我也将HEAD在上面替换branch为消除重写分支HEAD名称意味着什么的问题branch。
同时,我提供了一个无意义的树过滤器(不做任何更改,但是提供了一些输出)。因此,我的filter-branch命令是:
$ git filter-branch -f --tree-filter ls branch -- --since=2013-01-01 branch
Found nothing to rewrite
Run Code Online (Sandbox Code Playgroud)
现在让我们来揭露的内部运作方式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
Run Code Online (Sandbox Code Playgroud)
的-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
Run Code Online (Sandbox Code Playgroud)
(这将获得“要重写的正引用”列表;尽管有明显的“额外”,但此部分是正确的--)
+ test -s /tmp/t2/.git-rewrite/heads
Run Code Online (Sandbox Code Playgroud)
(这确保至少要重写一个分支名称)
+ pwd
+ GIT_INDEX_FILE=/tmp/t2/.git-rewrite/t/../index
+ export GIT_INDEX_FILE
Run Code Online (Sandbox Code Playgroud)
(这是索引过滤器等的更多设置)
+ 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
Run Code Online (Sandbox Code Playgroud)
这将检查要传递的参数,以git rev-list查找是否存在基于路径的修订限制器。它决定,有有:将-- since=...被视为一个pathspec,所以这台$dashdash空和remap_to_ancestors对t(简称真)。奇怪的是,$dashdash仅当我们提供了时才使用--subdirectory-filter,而我们没有提供。该代码看起来可疑,但它本身并不是问题的直接原因。
下一位:
+ git rev-parse --revs-only branch -- --since=2013-01-01 branch
Run Code Online (Sandbox Code Playgroud)
将要写入的rev列表写入临时文件(../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
Run Code Online (Sandbox Code Playgroud)
这会将参数更新为“仅传递给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'
Run Code Online (Sandbox Code Playgroud)
git rev-list上面的最后一个应该产生最后一组提交的重写。原始集合(来自--stdin和temp文件../parse)是正确的,但这已--since=... branch作为路径说明符(纯粹是限制修订版本)通过,而不是作为其他修订版本生成器(可能与一起添加修订版本--all)通过。
如果您使用手册页中的一些示例,例如(我将其修改为无操作):
git filter-branch --env-filter : -- --all
Run Code Online (Sandbox Code Playgroud)
他们之所以工作是因为git rev-parse了解--all,因此不会传递给最后一个git filter-branch:
+ git rev-list --reverse --topo-order --default HEAD --parents --simplify-merges --stdin
Run Code Online (Sandbox Code Playgroud)
实际上,--all导致refs进入parse文件(即--stdin内容),因此这适用于所有可到达的提交。
无论如何,虽然这太长了(因为我没有时间缩短它),但可以归结为一个事实,至少在目前,您不能--since在此处使用限制器。它们可能应该工作,但需要filter-branch脚本才能更巧妙地解析参数(也许在的帮助下git rev-parse)。如果最后一个“集合”未插入文字--,则该rev-list ... --stdin将会--since=... branch作为参数接收并做正确的事情。但是,对于实际的路径限制器,应该有一个--。
我尚不清楚错误是否在于过滤分支文档是否建议此处允许所有 rev-list选项(如果不允许),或者我强调的脚本部分周围的代码应该更聪明,或可能只是不同(例如,路径限制器可能需要两个 --参数)。但是无论如何,它一定是git中的bug,因为文档表明这--since可能有效,但事实并非如此。