設定與配置
取得與建立專案
基本快照
分支與合併
分享與更新專案
檢查與比較
修補
除錯
電子郵件
外部系統
伺服器管理
指南
管理
底層命令
- 2.44.1 → 2.47.0 無變更
-
2.44.0
02/23/24
- 2.29.3 → 2.43.5 無變更
-
2.29.2
10/29/20
- 2.25.2 → 2.29.1 無變更
-
2.25.1
02/17/20
-
2.25.0
01/13/20
- 2.24.1 → 2.24.4 無變更
-
2.24.0
11/04/19
- 2.22.1 → 2.23.4 無變更
-
2.22.0
06/07/19
- 2.18.1 → 2.21.4 無變更
-
2.18.0
06/21/18
- 2.16.6 → 2.17.6 無變更
-
2.15.4
12/06/19
-
2.14.6
12/06/19
-
2.13.7
05/22/18
-
2.12.5
09/22/17
- 2.10.5 → 2.11.4 無變更
-
2.9.5
07/30/17
-
2.8.6
07/30/17
- 2.3.10 → 2.7.6 無變更
-
2.2.3
09/04/15
- 2.1.4 無變更
-
2.0.5
12/17/14
概要
git filter-branch [--setup <command>] [--subdirectory-filter <directory>] [--env-filter <command>] [--tree-filter <command>] [--index-filter <command>] [--parent-filter <command>] [--msg-filter <command>] [--commit-filter <command>] [--tag-name-filter <command>] [--prune-empty] [--original <namespace>] [-d <directory>] [-f | --force] [--state-branch <branch>] [--] [<rev-list-options>…]
警告
git filter-branch 有許多陷阱,可能會產生不明顯的預期歷史重寫混亂(而且由於效能極差,您可能沒有時間調查這些問題)。這些安全性和效能問題無法向後相容地修復,因此不建議使用。請使用替代的歷史篩選工具,例如 git filter-repo。如果您仍然需要使用 git filter-branch,請仔細閱讀 安全性(和 效能)以了解 filter-branch 的地雷,然後盡可能避免其中列出的許多危險。
描述
讓您藉由重寫 <rev-list-options> 中提及的分支,並對每個修訂套用自訂篩選器來重寫 Git 修訂歷史。這些篩選器可以修改每個樹狀結構(例如,刪除檔案或在所有檔案上執行 perl 重寫)或有關每個提交的資訊。否則,所有資訊(包括原始提交時間或合併資訊)都將被保留。
該命令只會重寫命令列中提及的正面參考(例如,如果您傳遞 a..b,則只會重寫 b)。如果您未指定任何篩選器,則提交將在未進行任何變更的情況下重新提交,這通常不會有任何影響。儘管如此,這在未來可能對補償某些 Git 錯誤等很有用,因此允許這種用法。
注意:此命令會遵守 .git/info/grafts
檔案和 refs/replace/
命名空間中的參考。如果您有任何嫁接或取代參考定義,執行此命令將使其永久化。
警告!重寫的歷史記錄將對所有物件具有不同的物件名稱,並且不會與原始分支收斂。您將無法輕易地在原始分支之上推送和發布重寫的分支。如果您不了解全部含義,請不要使用此命令,如果一個簡單的單次提交就足以解決您的問題,請盡量避免使用。(有關重寫發布歷史的更多資訊,請參閱 git-rebase[1] 中的「從上游 rebase 復原」章節。)
請務必驗證重寫的版本是否正確:如果與重寫的參考不同,則原始參考將儲存在命名空間 refs/original/ 中。
請注意,由於此操作的 I/O 成本非常高,因此最好使用 -d
選項將臨時目錄重新導向到磁碟外,例如 tmpfs。據報導,速度提升非常顯著。
篩選器
篩選器會按照下方列出的順序套用。 <command> 引數始終會在 shell 環境中使用 eval 命令進行評估(由於技術原因,提交篩選器是例外)。在此之前,將設定 $GIT_COMMIT
環境變數以包含正在重寫的提交 ID。此外,GIT_AUTHOR_NAME、GIT_AUTHOR_EMAIL、GIT_AUTHOR_DATE、GIT_COMMITTER_NAME、GIT_COMMITTER_EMAIL 和 GIT_COMMITTER_DATE 會取自目前的提交,並匯出到環境中,以便影響 git-commit-tree[1] 在篩選器執行後所建立的取代提交的作者和提交者身分。
如果 <command> 的任何評估傳回非零結束狀態,則整個操作將中止。
有一個 map 函式可用,該函式會採用「原始 sha1 ID」引數,如果提交已被重寫,則會輸出「重寫的 sha1 ID」,否則會輸出「原始 sha1 ID」;如果您的提交篩選器發出多個提交,則 map 函式可以在不同的行上傳回多個 ID。
選項
- --setup <command>
-
這不是針對每個提交執行的真正篩選器,而是在迴圈之前的一次性設定。因此,尚未定義特定於提交的變數。此處定義的函式或變數可用於或修改在後續的篩選步驟中,但由於技術原因,提交篩選器除外。
- --subdirectory-filter <directory>
-
只查看觸及給定子目錄的歷史記錄。結果將包含該目錄(且僅該目錄)作為其專案根目錄。暗示 重新對應到祖先。
- --env-filter <command>
-
如果您只需要修改將執行提交的環境,則可以使用此篩選器。具體而言,您可能想要重寫作者/提交者姓名/電子郵件/時間環境變數(有關詳細資訊,請參閱 git-commit-tree[1])。
- --tree-filter <command>
-
這是用於重寫樹狀結構及其內容的篩選器。引數會在 shell 中評估,並將工作目錄設定為已簽出的樹狀結構的根目錄。然後,會按原樣使用新的樹狀結構(會自動新增新檔案,會自動刪除消失的檔案 - .gitignore 檔案或任何其他忽略規則都沒有任何作用!)。
- --index-filter <command>
-
這是用於重寫索引的篩選器。它與樹狀結構篩選器類似,但不簽出樹狀結構,這使其速度更快。通常與
git rm --cached --ignore-unmatch ...
一起使用,請參閱下方的範例。對於複雜的情況,請參閱 git-update-index[1]。 - --parent-filter <command>
-
這是用於重寫提交父項清單的篩選器。它會在 stdin 上接收父項字串,並應在 stdout 上輸出新的父項字串。父項字串的格式如 git-commit-tree[1] 中所述:初始提交為空,一般提交為 "-p parent",合併提交為 "-p parent1 -p parent2 -p parent3 …"。
- --msg-filter <command>
-
這是用於重寫提交訊息的篩選器。引數會在 shell 中評估,並將原始提交訊息放在標準輸入上;其標準輸出會用作新的提交訊息。
- --commit-filter <command>
-
這是用於執行提交的篩選器。如果指定了此篩選器,它會被呼叫來取代 git commit-tree 命令,並使用 "<TREE_ID> [(-p <PARENT_COMMIT_ID>)…]" 形式的引數,以及 stdin 上的記錄訊息。預期提交 ID 在 stdout 上。
作為特殊延伸,提交篩選器可能會發出多個提交 ID;在這種情況下,原始提交的重寫子項將會將所有這些提交 ID 作為父項。
您可以在此篩選器中使用 map 方便函式,以及其他方便函式。例如,呼叫 skip_commit "$@" 將會省略目前的提交(但不會省略其變更!如果您想要這樣做,請改用 git rebase)。
如果您不希望保留具有單一父項且不對樹狀結構進行任何變更的提交,您也可以使用
git_commit_non_empty_tree "$@"
來取代git commit-tree "$@"
。 - --tag-name-filter <command>
-
這是用於重寫標籤名稱的篩選器。傳遞此項時,它會針對每個指向重寫物件(或指向重寫物件的標籤物件)的標籤參考進行呼叫。原始標籤名稱會透過標準輸入傳遞,並且預期新的標籤名稱會在標準輸出上。
不會刪除原始標籤,但可以覆寫;使用 "--tag-name-filter cat" 來簡單更新標籤。在這種情況下,請務必小心,並確保您已備份舊標籤,以防轉換執行失敗。
幾乎支援正確地重寫標籤物件。如果標籤附加了訊息,將會建立一個新的標籤物件,並具有相同的訊息、作者和時間戳記。如果標籤附加了簽名,則簽名將會被移除。依照定義,不可能保留簽名。之所以說是「幾乎」正確,是因為理想情況下,如果標籤沒有變更(指向相同的物件、具有相同的名稱等),它應該保留任何簽名。但情況並非如此,簽名總是會被移除,請使用者注意。此外,也不支援變更作者或時間戳記(或標籤訊息)。指向其他標籤的標籤將會被重寫為指向底層的提交。
- --prune-empty
-
某些過濾器會產生空的提交,而這些提交不會更動樹狀結構。此選項指示 git-filter-branch 移除此類提交,如果它們只有一個或零個未修剪的父節點;合併提交將因此保持不變。此選項無法與
--commit-filter
一起使用,但可以使用提交過濾器中提供的git_commit_non_empty_tree
函數來達到相同的效果。 - --original <命名空間>
-
使用此選項設定原始提交將儲存的命名空間。預設值為 refs/original。
- -d <目錄>
-
使用此選項設定用於重寫的暫存目錄路徑。當套用樹狀結構過濾器時,命令需要將樹狀結構暫時簽出到某個目錄,這在大型專案的情況下可能會佔用大量空間。預設情況下,它會在
.git-rewrite/
目錄中執行此操作,但您可以使用此參數覆寫該選擇。 - -f
- --force
-
除非強制執行,否則 git filter-branch 會拒絕在現有的暫存目錄或已經存在以 refs/original/ 開頭的 refs 時啟動。
- --state-branch <分支>
-
此選項會導致從啟動時的命名分支載入舊物件到新物件的對應,並在結束時將其儲存為該分支的新提交,從而實現大型樹狀結構的遞增處理。如果 <分支> 不存在,則會建立它。
- <rev-list 選項>…
-
git rev-list 的參數。這些選項包含的所有正向 refs 都會被重寫。您也可以指定諸如
--all
之類的選項,但您必須使用--
將它們與 git filter-branch 選項分開。表示 重新映射到祖先。
重新映射到祖先
透過使用 git-rev-list[1] 參數,例如路徑限制器,您可以限制被重寫的修訂版本集合。但是,命令列上的正向 refs 會被區分:我們不讓它們被此類限制器排除。為此,它們會被重寫為指向未被排除的最近祖先。
範例
假設您要從所有提交中移除檔案(包含機密資訊或版權侵權)
git filter-branch --tree-filter 'rm filename' HEAD
但是,如果該檔案在某些提交的樹狀結構中不存在,則簡單的 rm filename
將會針對該樹狀結構和提交失敗。因此,您可能希望改為使用 rm -f filename
作為腳本。
將 --index-filter
與 git rm 一起使用會產生速度更快的版本。與使用 rm filename
一樣,如果檔案在提交的樹狀結構中不存在,則 git rm --cached filename
將會失敗。如果您想要「完全忘記」一個檔案,則它進入歷史的時間點並不重要,因此我們也新增 --ignore-unmatch
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
現在,您將在 HEAD 中儲存重寫的歷史記錄。
要重寫存放庫,使其看起來像是 foodir/
曾經是其專案根目錄,並捨棄所有其他歷史記錄
git filter-branch --subdirectory-filter foodir -- --all
因此,您可以例如將程式庫子目錄轉換為其自己的存放庫。請注意,--
將 filter-branch 選項與修訂版本選項分開,而 --all
則會重寫所有分支和標籤。
要設定提交(通常位於另一個歷史記錄的頂端)作為目前初始提交的父系,以便將另一個歷史記錄貼到目前歷史記錄的後面
git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD
(如果父系字串為空 - 當我們處理初始提交時會發生這種情況 - 則新增 graftcommit 作為父系)。請注意,這假設歷史記錄具有單一根目錄(也就是說,沒有發生沒有共同祖先的合併)。如果情況並非如此,請使用
git filter-branch --parent-filter \ 'test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>" || cat' HEAD
或更簡單的
git replace --graft $commit-id $graft-id git filter-branch $graft-id..HEAD
要從歷史記錄中移除由「Darl McBribe」撰寫的提交
git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ]; then skip_commit "$@"; else git commit-tree "$@"; fi' HEAD
函數 skip_commit 的定義如下
skip_commit() { shift; while [ -n "$1" ]; do shift; map "$1"; shift; done; }
移位魔術首先捨棄樹狀結構 ID,然後捨棄 -p 參數。請注意,這會正確處理合併!如果 Darl 在 P1 和 P2 之間提交合併,則它會正確傳播,並且合併的所有子系都會變成以 P1,P2 作為其父系而非合併提交的合併提交。
請注意,提交引入的變更,且未被後續提交還原的變更,仍將存在於重寫的分支中。如果您想要連同提交一起捨棄變更,則應該使用 git rebase 的互動模式。
您可以使用 --msg-filter
重寫提交日誌訊息。例如,由 git svn 建立的存放庫中的 git svn-id 字串可以透過這種方式移除
git filter-branch --msg-filter ' sed -e "/^git-svn-id:/d" '
如果您需要將 Acked-by 行新增到最後 10 次提交(其中沒有任何合併),請使用此命令
git filter-branch --msg-filter ' cat && echo "Acked-by: Bugs Bunny <bunny@bugzilla.org>" ' HEAD~10..HEAD
--env-filter
選項可用於修改提交者和/或作者身分。例如,如果您發現由於使用者電子郵件設定錯誤,導致您的提交具有錯誤的身分,您可以在發佈專案之前進行修正,如下所示
git filter-branch --env-filter ' if test "$GIT_AUTHOR_EMAIL" = "root@localhost" then GIT_AUTHOR_EMAIL=john@example.com fi if test "$GIT_COMMITTER_EMAIL" = "root@localhost" then GIT_COMMITTER_EMAIL=john@example.com fi ' -- --all
若要將重寫限制為僅限於部分歷史記錄,請在新的分支名稱之外指定修訂版本範圍。新的分支名稱將指向此範圍的 git rev-list 將列印的最頂層修訂版本。
考慮此歷史記錄
D--E--F--G--H / / A--B-----C
若要只重寫提交 D、E、F、G、H,但保留 A、B 和 C 不變,請使用
git filter-branch ... C..H
若要重寫提交 E、F、G、H,請使用以下其中一種
git filter-branch ... C..H --not D git filter-branch ... D..H --not C
若要將整個樹狀結構移動到子目錄中,或從那裡移除
git filter-branch --index-filter \ 'git ls-files -s | sed "s-\t\"*-&newsubdir/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new \ git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
縮減存放庫的檢查清單
git-filter-branch 可用於擺脫檔案的子集,通常是透過 --index-filter
和 --subdirectory-filter
的某些組合。人們期望產生的存放庫會比原始存放庫小,但您需要更多步驟才能實際縮小它,因為 Git 會盡力不遺失您的物件,直到您告訴它為止。首先請確定
-
您確實移除了檔案名稱的所有變體,如果 blob 在其生命週期中被移動過。
git log --name-only --follow --all -- filename
可以協助您找到重新命名。 -
您確實過濾了所有 refs:在呼叫 git-filter-branch 時使用
--tag-name-filter cat -- --all
。
然後有兩種方法可以取得較小的存放庫。較安全的方法是複製,這會保持您的原始版本完好無損。
-
使用
git clone file:///path/to/repo
複製它。複製版本將沒有移除的物件。請參閱 git-clone[1]。(請注意,使用純路徑複製只會硬連結所有內容!)
如果您真的不想複製它,無論基於什麼原因,請檢查以下幾點(按此順序)。這是一種非常具破壞性的方法,因此請建立備份或返回複製它。您已被警告。
-
移除 git-filter-branch 備份的原始 refs:例如
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
。 -
使用
git reflog expire --expire=now --all
使所有 reflog 過期。 -
使用
git gc --prune=now
來垃圾收集所有未參考的物件(或者如果您的 git-gc 版本不夠新到支援--prune
的參數,請改用git repack -ad; git prune
)。
效能
git-filter-branch 的效能極其緩慢;其設計使得向後相容的實作永遠無法快速
-
在編輯檔案時,git-filter-branch 依設計會簽出在原始存放庫中存在的每個提交。如果您的存放庫有
10^5
個檔案和10^5
個提交,但每個提交只修改五個檔案,則 git-filter-branch 會讓您執行10^10
次修改,儘管只有(最多)5*10^5
個唯一的 blob。 -
如果您嘗試作弊並嘗試讓 git-filter-branch 只處理在提交中修改的檔案,則會發生兩件事
-
每當使用者只是嘗試重新命名檔案時,您就會遇到刪除問題(因為嘗試刪除不存在的檔案看起來像是無操作;當重新命名是透過任意使用者提供的 shell 發生時,需要一些詭計才能重新映射檔案重新命名的刪除)
-
即使您成功地針對重新命名執行了 map-deletes 詭計,您仍然在技術上違反了向後相容性,因為允許使用者以取決於提交拓撲的方式篩選檔案,而不是僅根據檔案內容或名稱進行篩選(儘管在實際操作中並未觀察到這種情況)。
-
-
即使您不需要編輯檔案,而只想例如重新命名或移除一些檔案,因此可以避免簽出每個檔案(也就是說,您可以使用 --index-filter),您仍然會傳遞 shell 片段來進行篩選。這表示對於每個提交,您都必須準備一個可以執行這些過濾器的 git 存放庫。這是一個重要的設定。
-
此外,git-filter-branch 會針對每個提交建立或更新多個額外檔案。其中一些是為了支援 git-filter-branch 提供的便利函數(例如 map()),而另一些則是為了追蹤內部狀態(但也可能被使用者過濾器存取;git-filter-branch 的其中一個迴歸測試會這樣做)。這基本上等於使用檔案系統作為 git-filter-branch 和使用者提供的過濾器之間的 IPC 機制。磁碟往往是速度較慢的 IPC 機制,並且寫入這些檔案也有效地代表我們在每次提交時都會遇到的個別程序之間的強制同步點。
-
使用者提供的 shell 命令可能會包含一系列命令,導致每個提交建立許多程序。建立和執行另一個程序在作業系統之間需要不同的時間,但在任何平台上,相較於呼叫函數,速度都非常慢。
-
git-filter-branch 本身是用 shell 撰寫的,這有點慢。這是唯一可以向後相容地修正的效能問題,但與 git-filter-branch 設計固有的上述問題相比,工具本身的語言是相對次要的問題。
-
附註:很遺憾地,人們往往會執著於 shell 腳本的撰寫方式,並定期詢問是否能用其他程式語言重寫 git-filter-branch,以解決效能問題。這不僅忽略了設計上更大的內在問題,而且效果也比你預期的要小:如果 git-filter-branch 本身不是 shell 腳本,那麼便利函式 (map()、skip_commit() 等) 和
--setup
參數將無法在程式開始時執行一次,而是需要預先加到每個使用者篩選器中 (因此每次提交都要重新執行)。
-
git filter-repo 工具是 git-filter-branch 的替代方案,它不會遇到這些效能問題或安全性問題(如下所述)。對於那些現有工具依賴 git-filter-branch 的人,git filter-repo 也提供了 filter-lamely,這是一個隨插即用的 git-filter-branch 替代品(有一些注意事項)。雖然 filter-lamely 遭受與 git-filter-branch 相同的所有安全性問題,但至少可以稍微改善效能問題。
安全性
git-filter-branch 充滿了陷阱,導致各種容易損壞儲存庫或最終結果比開始時更糟的情況
-
有些人可能有一套「運作良好且經過測試的篩選器」,他們將其記錄下來或提供給同事,然後同事在不同的作業系統上執行這些篩選器,而這些篩選器在不同的作業系統上可能無法運作/未經測試(git-filter-branch 手冊頁中的一些範例也會受到影響)。BSD 與 GNU 使用者空間的差異可能會帶來很大的麻煩。如果幸運的話,會出現錯誤訊息。但同樣有可能的是,這些命令要么沒有執行所要求的篩選,要么通過進行一些不想要的更改而靜默地損壞。不想要的更改可能只會影響少數提交,因此也不一定很明顯。(問題不一定很明顯的事實意味著它們很可能在重寫的歷史記錄使用相當長的時間後才會被注意到,到那時,就很難再為另一次重寫找理由了。)
-
包含空格的檔名通常會被 shell 片段錯誤處理,因為它們會對 shell 管道造成問題。並非所有人都熟悉 find -print0、xargs -0、git-ls-files -z 等。即使熟悉這些的人也可能認為這些標誌無關緊要,因為在執行篩選的人加入專案之前,其他人已經重新命名了他們儲存庫中的任何此類檔案。而且,即使熟悉處理帶有空格的引數的人也可能沒有這樣做,因為他們並沒有考慮到所有可能出錯的情況。
-
儘管非 ASCII 檔名位於所需的目錄中,也可能會被靜默刪除。通常使用類似
git ls-files | grep -v ^WANTED_DIR/ | xargs git rm
的管道來僅保留所需的路徑。ls-files 僅在需要時才會引用檔名,因此人們可能不會注意到其中一個檔案與正則表示式不匹配(至少在為時已晚之前不會)。是的,知道 core.quotePath 的人可以避免這種情況(除非他們有其他特殊字元,如 \t、\n 或 "),而使用 ls-files -z 和其他東西而不是 grep 的人可以避免這種情況,但這並不意味著他們會這樣做。 -
同樣,在移動檔案時,人們可能會發現帶有非 ASCII 或特殊字元的檔名最終會出現在不同的目錄中,其中一個目錄包含雙引號字元。(這在技術上與上面的引號問題相同,但它可能以另一種有趣的方式作為問題出現。)
-
非常容易意外地混淆舊的歷史記錄和新的歷史記錄。使用任何工具仍然有可能,但 git-filter-branch 幾乎是在邀請這樣做。如果幸運的話,唯一的缺點是使用者會因為不知道如何縮小他們的儲存庫和刪除舊的東西而感到沮喪。如果不幸的話,他們會合併舊的歷史記錄和新的歷史記錄,並最終得到每個提交的多個「副本」,其中一些提交包含不想要的或敏感的檔案,而另一些則不包含。這會以多種不同的方式發生
-
預設情況下僅執行部分歷史記錄重寫(--all 不是預設值,而且很少有範例顯示它)
-
沒有自動的執行後清理
-
--tag-name-filter(當用於重新命名標籤時)不會刪除舊標籤,而只是新增帶有新名稱的新標籤
-
很少提供教育資訊來告知使用者重寫的後果以及如何避免混淆舊的歷史記錄和新的歷史記錄。例如,此手冊頁討論了使用者需要了解他們需要將所有分支的變更基於新的歷史記錄之上(或刪除並重新克隆),但這只是需要考慮的多個問題之一。有關更多詳細資訊,請參閱 git filter-repo 手冊頁的「討論」部分。
-
-
由於以下兩個問題中的任何一個,帶註釋的標籤可能會意外地轉換為輕量級標籤
-
有人可能會執行歷史記錄重寫,意識到自己搞砸了,從 refs/original/ 中的備份還原,然後重新執行他們的 git-filter-branch 命令。(refs/original/ 中的備份不是真正的備份;它首先會取消標籤的引用。)
-
在您的 <rev-list-options> 中使用 --tags 或 --all 執行 git-filter-branch。為了將帶註釋的標籤保留為帶註釋的標籤,您必須使用 --tag-name-filter(並且不得在先前搞砸的重寫中從 refs/original/ 還原)。
-
-
任何指定編碼的提交訊息都會因重寫而損壞;git-filter-branch 會忽略編碼,取得原始位元組,並將其傳送到 commit-tree,而不會告訴它正確的編碼。(無論是否使用 --msg-filter,都會發生這種情況。)
-
提交訊息(即使它們都是 UTF-8)預設情況下也會損壞,因為它們沒有更新 — 提交訊息中對其他提交雜湊的任何引用現在都將指向不再存在的提交。
-
沒有任何設施可以幫助使用者找到他們應該刪除的不需要的垃圾,這意味著他們更有可能進行不完整或部分清理,這有時會導致混亂,並讓人們浪費時間試圖理解。(例如,人們傾向於只尋找要刪除的大型檔案,而不是大型目錄或副檔名,一旦他們這樣做了,那麼稍後使用新儲存庫並瀏覽歷史記錄的人就會注意到一個構建工件目錄,其中有一些檔案但沒有其他檔案,或者一個依賴項的快取 (node_modules 或類似的),由於缺少某些檔案,它永遠不可能正常運作。)
-
如果未指定 --prune-empty,則篩選過程可能會產生大量令人困惑的空提交
-
如果指定了 --prune-empty,則篩選操作之前有意放置的空提交也會被修剪,而不僅僅是修剪因篩選規則而變為空的提交。
-
如果指定了 --prune-empty,有時會錯過空提交並將其保留下來(一個有些罕見的錯誤,但它會發生…)
-
一個小問題是,目標是更新儲存庫中所有名稱和電子郵件的使用者可能會被引導到 --env-filter,它只會更新作者和提交者,而遺漏標籤者。
-
如果使用者提供一個 --tag-name-filter,將多個標籤對應到相同的名稱,則不會提供警告或錯誤;git-filter-branch 只是以某種未記錄的預定義順序覆寫每個標籤,最終只剩一個標籤。(git-filter-branch 回歸測試需要這種令人驚訝的行為。)
此外,git-filter-branch 的效能不佳通常會導致安全問題
-
除非您只是進行簡單的修改,例如刪除幾個檔案,否則有時很難提出正確的 shell 片段來執行您想要的篩選。不幸的是,人們通常通過嘗試來了解片段是否正確,但正確與否可能會因特殊情況而異(檔名中的空格、非 ASCII 檔名、奇怪的作者姓名或電子郵件、無效的時區、graft 或 replace 物件的存在等),這意味著他們可能必須等待很長時間、遇到錯誤,然後重新啟動。git-filter-branch 的效能非常差,以至於這個週期很痛苦,減少了仔細重新檢查的時間(更不用說它對執行重寫的人的耐心造成的影響,即使他們在技術上擁有更多可用時間)。這個問題尤其複雜,因為損壞的篩選器造成的錯誤可能很長時間都不會顯示,並且/或者會淹沒在大量的輸出中。更糟糕的是,損壞的篩選器通常只會導致靜默的錯誤重寫。
-
最重要的是,即使使用者最終找到可運作的命令,他們自然也會想要分享這些命令。但他們可能不知道他們的儲存庫沒有其他人的儲存庫具有的某些特殊情況。因此,當另一個具有不同儲存庫的人執行相同的命令時,他們會遇到上述問題。或者,使用者只是執行了經過特殊情況審核的命令,但他們在另一個無法運作的作業系統上執行了這些命令,如上所述。
GIT
git[1] 套件的一部分