我複製了一個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