2016-11-28 70 views
0

我需要從裸倉庫中的git歷史記錄中連續清除20個提交。 我嘗試使用下面的命令,(請注意,我不想寫全長哈希值,並嘗試使用子字符串比較):如何使用--commit-filter在一個git filter-branch pass中排除20提交?

git filter-branch -d /dev/shm/scratch --commit-filter ' 
if [ ${GIT_COMMIT0:7} = e687d59 ] || 
    [ ${GIT_COMMIT0:7} = 58daf29 ] || 
    ... 
    [ ${GIT_COMMIT0:7} = 682b2c2 ] || 
    [ ${GIT_COMMIT0:7} = 947db9e ]; 
    then 
      skip_commit "[email protected]"; 
    else 
      git commit-tree "[email protected]"; 
    fi' --tag-name-filter cat -- --all 

但我立即得到消息,如:

重寫414840693169a74d052548c7a7a1bc5b06d3b79c(一萬零三百六十零分之一)(0秒 通過,剩餘的0預測的)git的承諾樹:49:的git 提交樹:壞取代寫不出重寫提交

無論是OR條件還是子串都存在錯誤,我無法弄清楚。

我也有另外一個問題:我怎樣才能登錄使用舊的映射文件的散列到一個新的時git filter-branch完成它的工作?

回答

1

的基本問題是這樣的:

if [ ${GIT_COMMIT0:7} = e687d59 ] || 
    [ ${GIT_COMMIT0:7} = 58daf29 ] || 
    ... 
    [ ${GIT_COMMIT0:7} = 682b2c2 ] || 
    [ ${GIT_COMMIT0:7} = 947db9e ]; 

是錯誤的。

子串的bash語法是${name:offset:length},在這種情況下,它將是${GIT_COMMIT:0:7},即您缺少冒號。

但:

  • git filter-branch爲SH(未bash)的腳本;
  • 過濾器分支腳本使用eval;和
  • 無論如何,這並不是最好的方法。

前兩個意思是你不能依賴於bash特定的語法。

第三種意思是沒有真正的理由這樣做。

一種選擇是使用[(又名test)計劃的-o(或)運算符:

if [ $GIT_COMMIT = ... -o 
    $GIT_COMMIT = ... -o 
    ... 
    $GIT_COMMIT = ... ]; then 

但是這仍然太痛苦了,在我看來。取而代之的是,爲什麼不使用grep,例如:

if echo $GIT_COMMIT | grep -F -f /tmp/list >/dev/null; then 

該文件/tmp/list包含要跳過的ID?如果grep發現其中一個,它將以零(成功)狀態退出,否則它以非零(失敗)狀態退出,這與test[程序在測試成功時退出0相同,如果失敗則退出非零。

(如果您的grep有-q,您可以使用,而不是重定向到/dev/null

0

三樣東西嘗試 - 我還沒有出現過這種情況我自己,所以沒有測試過任何人。

  1. 的子串應${GIT_COMMIT:0:7}而非${GIT_COMMIT0:7}(變量名後冒號)

  2. 代替--tag-name-filter cat -- --all,使用HEAD。該man page給出了一個相關的例子:

    要從歷史記錄中刪除提交內容「卡爾McBribe」創作:

    git filter-branch --commit-filter ' 
         if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ]; 
         then 
           skip_commit "[email protected]"; 
         else 
           git commit-tree "[email protected]"; 
         fi' HEAD 
    
       ^^^^ 
    

    請注意,指定HEAD足夠清潔,該庫例。

  3. 使用bash測試,而不是test(1)(應該更快,更穩健):

    if [[ ${GIT_COMMIT0:7} = e687d59 || ${GIT_COMMIT0:7} = 58daf29 || ... ]]; then 
    
+1

只是使用'如果有其他分支分支出來的_after_改寫歷史HEAD'是壞。 – j6t

+0

@ j6t感謝您的提示 – cxw

2

我會把它寫成

git filter-branch -d /dev/shm/scratch --commit-filter ' 
    case $GIT_COMMIT in 
    e687d59*|58daf29*|682b2c2*|947db9e*) 
     skip_commit "[email protected]" 
     ;; 
    *) 
     git commit-tree "[email protected]" 
     ;; 
    esac' --tag-name-filter cat -- --all 

這不是遠遠大於你的說法更好(你有後修正它指出),但仍然少打字。

如果你知道一個提交這些被改寫之前,它可能會還清增加它像這樣:

... --tag-name-filter cat -- --all --not that_commit