簡體   English   中英

使用git filter-branch進行特定的提交

[英]Using git filter-branch for specific commits

我正在嘗試使用git filter-branch功能來刪除最近更新並提交的文件。 我嘗試運行以下命令:

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- 6f7fda9..HEAD

但是,這只會從master分支中刪除文件,而我希望將其從所有分支中刪除。

從將6f7fda9提交到HEAD開始,我希望刪除文件。 我執行的命令是否錯誤?

git filter-branch -- --all all在所有分支上運行過濾器。 所以:

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- --all

我想從所有分支中刪除[文件]

重要的是要意識到分支幾乎(但不是完全)無關。 重要的是提交

您實際上無法更改任何現有的提交,並且Git不會嘗試。 git filter-branch所做的是復制提交。 也就是說,對於每個要過濾的提交,Git都會將其提取到一個臨時工作區中,應用您的過濾器,然后從結果中進行一個新的提交。

如果新提交與原始提交逐位相同,則它將重新使用存儲庫數據庫中的實際基礎對象。 如果不是(目的是導致結果為“ not”),則將保留原始提交,而新副本將獲得新的,不同的哈希ID。 如果我們使用大寫字母代替提交哈希ID,並記住每個提交都存儲其父提交的哈希ID,則可以通過以下方式繪制原始文檔:

... <-F <-G <-H <-I   <-- master

master這樣的分支名稱會記住上一次提交的哈希ID。 該提交會記住其父級的哈希ID,並記住另一個父級的另一個哈希ID,依此類推: master讓Git 找到提交I ,然后找到提交H ,然后找到提交G ,依此類推。

使用git filter-branch我們告訴Git: 提取commit F並對其進行一些更改,然后重新提交。 如果F沒有任何變化,我們將保留實際的哈希ID。 然后,我們將Git提取為commit G並進行一些更改。 這次,也許我們刪除了一個敏感文件。 因此,我們進行了一個類似於G的新提交,但有所不同:它獲得了一個新的,不同的哈希ID,我們可以將其稱為G' 提交G'仍將提交F作為其父級:

...--F--G--H--I   <-- master
      \
       G'

然后,我們提取H並應用過濾器。 即使沒有其他改變,我們也需要新的提交指向G' ,所以filter-branch確保了這種情況的發生,因此我們得到了指向G'的提交H' G' 我們為I重復I ,結果是:

...--F--G--H--I   <-- master
      \
       G'-H'-I'

最后一步是git filter-branch重寫每個分支名稱 該名master現在必須指向犯I' ,其新的和不同的哈希,不破舊惡心I

git filter-branch在處理結束時重寫的名稱是您在命令行上肯定標識的所有名稱。 這部分有些棘手: git filter-branch將適合git rev-list字符串用作其某些參數。 這些可以是正引用(例如master ,也可以是負引用(例如^develop^6f7fda9

否定引用告訴Git: 不要為這些提交打擾 如果使用^6f7fda9跳過提交6f7fda9以及提交之前(按圖形顯示)的任何內容,則git filter-branch不必花費任何計算機時間來執行該提交。

表達式6f7fda9..HEAD^6f7fda9 HEAD簡寫,並且HEAD表示當前分支名稱 因此,這是對一個分支名稱(例如master )的正向引用 ,而對哈希ID的一個負向引用。

您可以使用--branches來命名所有分支名稱。 您可以使用--all來命名所有引用 (包括不是分支名稱的內容)。 Filter-branch將只重寫肯定引用,但會重寫所有引用。 請注意這一點,因為這可能會重寫refs/stash

重寫任何分支,標簽,或其他指的是一些名稱提交, 包含你希望有這個文件,你會得到的東西,如:

                    tip2   [abandoned]
                   /
...--good--bad--...--tip   [abandoned]
       \
        copied--...--tip'   <-- branch1
                   \
                    tip2'   <-- branch2

如果您重寫某些名稱,該名稱從bad到下(向右)指向任何提交,則這些名稱仍將指向具有您要刪除的文件的“壞”提交。 (請記住,在我在StackOverflow上執行的這些特定圖形繪圖中,較早的/父提交位於左側,稍后的/子提交位於右側。)

所述的要求是矛盾的。 特別

我希望將其從所有分支中刪除。

從將6f7fda9提交到HEAD開始,我希望刪除文件。

需要和解。 我懷疑這歸結為對提交范圍的不正確理解-只是git中的一種。

考慮以下提交圖:

x -- 6f7fda9 -- A -- B -- C -- F <--(master)
                 \                        ^(HEAD)
                  D -- E <--(branch)

所以HEADF master那里; 並且有一個分支(顯然)是從A創建A (在6f7fda9之后但在HEAD之前)。

現在的問題是,給定該圖, 6f7fda9..HEAD是什么意思? 不幸的是,答案並不是很多人憑直覺想到的。

6f7fda9..HEAD是短期的HEAD ^6f7fda9 -意思是“一切從到達HEAD但從可達6f7fda9 ”。 “可達到”是指“提交本身,以及通過遵循父指針找到的所有提交”。 因此,在這種情況下,它表示ABCF 但不是x6f7fda9 (因為它們可以從6f7fda9到達),也不能是DE (因為它們不能從HEAD到達)。

有幾種方法可以使filter-branch處理所有分支。 例如你可以

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- --all

但這將包括所有引用(不僅是所有分支); 如果有問題

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- --branches

另一項警告-如果您特別希望在重寫6f7fda9之前提交,那么您需要包括一個或多個否定提交引用。 但是,如果您確實打算包括6f7fda9本身, 6f7fda9排除其父項(而不是其自身)。

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- ^6f7fda9^ --branches

如果6f7fda9是合並,則必須為其每個父項列出否定提交引用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM