2014-09-02 60 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