Git Filter-Repo是用於重寫歷史記錄的多功能工具,其中包括我在其他任何地方都沒有找到的功能。它大致與Git Filter-Branch的工具空間大致相同,但沒有引起投降的性能較差,具有更多功能,並且設計可在可用性方面擴展,超出了微不足道的重寫案例。現在,Git Project推薦Git Filter-Repo而不是Git Filter-Branch。
雖然大多數用戶可能只會將過濾器repo用作簡單的命令行工具(並且可能只使用其一些標誌),但在其核心過濾器中,repo包含一個用於創建歷史記錄重寫工具的庫。因此,具有專業需求的用戶可以利用它來快速創建全新的歷史記錄重寫工具。
過濾器repo需要:
git-filter-repo
是一個單文件python腳本,它是為了在許多系統上進行基本使用的安裝而進行的:只需將文件放入您的$路徑中即可。
有關基本用法或特殊情況以外的內容,請參見install.md。僅當適用以下一個應用時,需要越多的指示:
用於綜合文檔:
如果您喜歡從示例中學習:
有關過濾器repo的Git Rev新聞文章中,這是更詳細介紹的,但是對於主要競爭對手來說,一些亮點是:
對於非瑣事存儲庫,濾波器分支極為緩慢(比應該慢的多個數量級)。
Filter-Cranch充滿了陷阱,可以使您的重寫默默破壞或至少阻止您的“清理”努力,這比您最初的問題更有問題和混亂。
過濾器分支非常繁重,用於任何重寫甚至略有無事的重寫。
GIT項目指出,上述過濾器分支的問題不能向後兼容。他們建議您停止使用過濾器分支
過濾器分支的頑固迷可能對濾波器(又名濾波器- 分支機構)感興趣,這是基於過濾器repo的過濾器分支的重新實現,該濾波器更具性能(儘管不如過濾器- 不如過濾器- repo)。
有一個備忘單,顯示如何將示例命令從過濾器 - 布蘭奇手冊中轉換為filter-repo命令。
當時的好工具很棒,但是儘管它使一些事情變得簡單,但它僅限於一些重寫。
它的架構不適合處理更多類型的重寫。
它的架構甚至是針對其預期的用戶酶的一些缺點和錯誤。
BFG的粉絲可能對BFG-ish感興趣,BFG-ish是基於Filter-Repo的BFG的重新實現,其中包括相對於BFG的幾個新功能和錯誤。
有一個備忘單顯示瞭如何將示例命令從BFG回購器的手冊轉換為filter-repo命令。
假設我們要提取一個存儲庫,目的是將該件合併到其他一些更大的存儲庫中。為了提取,我們想:
使用filter-repo進行此操作與以下命令一樣簡單:
git filter-repo --path src/ --to-subdirectory-filter my-module --tag-rename ' ' : ' my-module- '
(單引號是不必要的,但要使人更清楚地說,我們正在用my-module-
取代空字符串作為前綴 - )
BFG回購清潔器無法進行這種改寫;實際上,所有三種想要的更改都超出了其功能。
過濾器分支帶有一堆警告(以下更多內容),即使您弄清楚了必要的調用:
git filter-branch
--tree-filter ' mkdir -p my-module &&
git ls-files
| grep -v ^src/
| xargs git rm -f -q &&
ls -d *
| grep -v my-module
| xargs -I files mv files my-module/ '
--tag-name-filter ' echo "my-module-$(cat)" '
--prune-empty -- --all
git clone file:// $( pwd ) newcopy
cd newcopy
git for-each-ref --format= " delete %(refname) " refs/tags/
| grep -v refs/tags/my-module-
| git update-ref --stdin
git gc --prune=now
有些人可能會注意到,由於使用-tree-filter,上述過濾器分支調用確實會很慢。您也可以使用過濾器分支的 - 索引濾波器選項,將上述命令更改為:
git filter-branch
--index-filter ' git ls-files
| grep -v ^src/
| xargs git rm -q --cached;
git ls-files -s
| sed "s%$(printf \t)%&my-module/%"
| git update-index --index-info;
git ls-files
| grep -v ^my-module/
| xargs git rm -q --cached '
--tag-name-filter ' echo "my-module-$(cat)" '
--prune-empty -- --all
git clone file:// $( pwd ) newcopy
cd newcopy
git for-each-ref --format= " delete %(refname) " refs/tags/
| grep -v refs/tags/my-module-
| git update-ref --stdin
git gc --prune=now
但是,對於任何一個過濾器 - 分支命令,都有一堆警告。首先,有些人可能想知道為什麼我在此處列出五個命令進行過濾器分支。儘管使用了 - all和 - 標記名稱過濾器,以及過濾器 - 布蘭奇(Filter-Branch)聲稱克隆足以擺脫舊對象,但刪除其他標籤並執行另一個GC的額外步驟仍需要清理舊物體,並避免將新的和舊曆史混合在某個地方。其他警告:
一個人可以將其與類似的東西一起入侵:
git fast-export --no-data --reencode=yes --mark-tags --fake-missing-tagger
--signed-tags=strip --tag-of-filtered-object=rewrite --all
| grep -vP ' ^M [0-9]+ [0-9a-f]+ (?!src/) '
| grep -vP ' ^D (?!src/) '
| perl -pe ' s%^(M [0-9]+ [0-9a-f]+ )(.*)$%1my-module/2% '
| perl -pe ' s%^(D )(.*)$%1my-module/2% '
| perl -pe s%refs/tags/%refs/tags/my-module-%
| git -c core.ignorecase=false fast-import --date-format=raw-permissive
--force --quiet
git for-each-ref --format= " delete %(refname) " refs/tags/
| grep -v refs/tags/my-module-
| git update-ref --stdin
git reset --hard
git reflog expire --expire=now --all
git gc --prune=now
但這帶來了一些令人討厭的警告和局限性:
現有的存儲庫過濾工具都沒有做我想要的。他們都滿足我的需求。沒有工具提供下面我想要的前八個特徵中的任何一個,也沒有工具提供最後四個特徵中的兩個以上:
[起始報告]為用戶提供了對其存儲庫的分析,以幫助他們開始修改或重命名的內容,而不是期望他們猜測或找到其他工具來弄清楚它。 (觸發,例如,第一次使用特殊標誌(例如 - 分析)運行。)
[保持與刪除]不僅為用戶提供一種輕鬆刪除所選路徑的方式,還為用戶提供標誌以僅保留某些路徑。當然,用戶可以通過指定除了要保留的路徑以外的所有路徑來解決此問題,但是需要指定任何版本中任何版本中存在的所有路徑有時可能會很痛苦。用於過濾器分支,使用諸如git ls-files | grep -v ... | xargs -r git rm
可能是一個合理的解決方法,但可能會變得笨拙,對用戶來說並不那麼簡單。再加上這些命令通常是特定於操作系統的(您可以在我提供的摘要中發現GNUism嗎?)。
[重命名]重命名路徑應該很容易。例如,除了允許一個人將某個子目錄視為存儲庫的根源外,還為用戶提供了使存儲庫的根源的選項,只是成為一個子目錄。通常,更允許文件和目錄易於重命名。提供理智檢查,如果重命名導致多個文件在同一路徑上存在。 (並添加特殊處理,以便如果提交僅複製oldname-> newname而無需修改,則過濾OldName-> NewName不會觸發理智檢查並在該提交上死亡。)
[更智能的安全]編寫原始參考文獻副本,以在存儲庫中的特殊名稱空間中提供不友好的恢復機制。許多人會很難使用它來恢復。我見過的幾乎每個人都做了一個存儲庫過濾操作,因此使用了一個新鮮的克隆,因為在錯誤的情況下擦除克隆是一種非常容易的恢復機制。如果我們不在新鮮的克隆中,則強烈鼓勵通過檢測和保釋來鼓勵工作流程,除非用戶覆蓋(用戶)。
[自動收縮]過濾後自動卸下舊的cruft並為用戶重新包裝存儲庫(除非覆蓋);這簡化了用戶的內容,有助於避免將新舊曆史和新歷史混合在一起,並避免在縮小Manpage中記錄的多個倉庫的多步驟過程中實際上在某些情況下不起作用的問題。 (我在看著你,過濾分支。)
[清潔分離]避免使用戶混淆(並防止將舊的存儲庫和重寫的存儲庫混合在一起,以防止意外重新刷新舊物品。 (使用 - 標籤名稱濾波器選項時,這尤其是濾波器分支的問題,有時也是一個問題時,當僅濾波分支的子集時也是一個問題。)
[多功能性]為用戶提供了擴展工具甚至編寫新工具的能力,以利用現有功能,並以(a)避免需要單獨的過程(會破壞性能)的方式提供這種可擴展性,(b )避免使用戶指定與OS相關的外殼命令(這將阻止用戶彼此共享命令),(c)利用豐富的數據結構(因為Hashes,Dict,dict,列表和數組在Shell中很難)和( d)提供合理的字符串操縱功能(外殼中缺乏)。
[舊提交引用]為用戶提供了一種使用新存儲庫的舊提交ID(尤其是通過REFS/ replot/ references從舊哈希映射到新哈希的映射)。
[提交消息一致性]如果提交消息請參閱ID的其他提交(例如“ This this revers Commit 01234567890ABCDEF”,“在COMMIT 0013DEADBEEF9A ...”中,應將這些提交消息重寫以引用新提交ID。
[變成空的修剪]應修剪由於過濾而變為空的提交。如果將提交的父母修剪,則第一個非封閉的祖先需要成為新父母。如果不存在非統治的祖先,並且該提交不是合併,那麼它將成為一個新的根源提交。如果不存在非統治的祖先,並且該提交是合併的,那麼合併將少一個父母(因此,如果它沒有自己的文件更改,則可能會成為一個非合併犯罪的犯罪。 。這裡要注意的一件特殊的事情是,我們修剪命令會變為空,而不是開始空虛。有些項目故意出於版本控製或發布原因創建空委託,不應將其刪除。 (作為特殊情況,提交開始空虛,但將父母修剪的父母也將被認為是“空的”。)
[變成降級的修剪]變為空的委員會修剪可能會導致拓撲變化,並且有很多特殊情況。通常,由於需要保留圖形拓撲,因此不會刪除合併提交,但是父母和其他祖先的修剪最終可能導致一個或多個父母的損失。上面已經指出了一個簡單的案例:如果合併提交失去了足夠多的父母成為非合併提交,並且沒有文件更改,那麼它也可以修剪。合併提交也可以具有變性的拓撲:最終可能會成為父母兼職的Merge_base(如果所有介入原始倉庫的所有乾預都均已修剪),或者可能最終與一位父母在一起,這是其另一個父母的祖先父母。在這種情況下,如果合併沒有自己的文件更改,則也可以修剪合併提交。但是,就像我們在空的修剪時一樣,我們不修剪開始合併開始墮落的提交(這表明它可能是故意的,例如與- no-ff合併),但只有合併的承諾會變成墮落,沒有任何文件更改的文件更改他們自己的。
[速度]過濾應合理的快速
請參閱貢獻指南。
預計過濾器repo社區的參與者將遵守與GIT項目相同的標準,因此GIT行為守則適用。
在Filter-Repo及其前任方面的工作還為核心GIT中的快速進出和快速IMPORT(以及其他命令)進行了許多改進,基於Filter-Repo需要做的工作: