簡體   English   中英

是否可以在不重寫歷史記錄的情況下縮小.git存儲庫?

[英]Is it possible to slim a .git repository without rewriting history?

由於二進制測試文件和java .jar文件的歷史包含,我們有許多git存儲庫已經增長到難以管理的大小。

我們正要進行git filter-branch這些存儲庫的練習,在它們被使用的任何地方重新克隆它們(從幾十個到幾百個部署,取決於repo)並且考慮到重寫歷史問題我想知道如果可能有任何其他解決方案。

理想情況下,我想在不重寫每個存儲庫的歷史記錄的情況下將問題文件外部化。 理論上這應該是可能的,因為你檢查相同的文件,具有相同的大小和相同的哈希值,只是從不同的地方(遠程而不是本地對象存儲)獲取它們。 到目前為止,我找到的任何潛在解決方案似乎都不允許我這樣做。

git-annex開始,我能找到解決問題的最接近的方法是如何追溯性地附加一個已經存在於git倉庫中的文件 ,但就像刪除大文件一樣,這需要重新編寫歷史記錄以進行轉換原來的git addgit annex add

從那里開始,我開始查看git-annex不是所列出的其他項目,所以我檢查了git-bigfilesgit-mediagit-fat 不幸的是,我們不能使用的混帳bigfilesgit ,因為我們是一個Eclipse 和使用的混合物git例如:It 它看起來不像git-mediagit-fat也可以做我想要的,因為雖然你可以用外部等價物替換現有的大文件,但你仍然需要重寫歷史記錄以刪除已經存在的大文件一直致力於。

那么,是否可以在不重寫歷史記錄的情況下縮小.git存儲庫,或者我們是否應該回到使用git filter-branch和一大堆重新部署的計划?


順便說一句,相信這應該是可能的,但可能與git當前淺層克隆實現的限制相同。

Git已經為同一個blob支持多個可能的位置,因為任何給定的blob都可以在松散的對象存儲.git/objects )或包文件 (.git / objects)中,所以理論上你只需要像git-annex這樣的東西在這個級別而不是更高級別(例如,如果你願意,可以按需下載遠程blob的概念)。 不幸的是,我找不到任何人已經實施甚至建議這樣的事情。

有點。 您可以使用Git的替換功能來預留大膨脹歷史記錄,以便僅在需要時下載。 它就像一個淺層克隆,但沒有淺層克隆的限制。

這個想法是你通過創建一個新的root提交來重新啟動分支,然后挑選舊分支的提示。 通常你會以這種方式丟失所有的歷史記錄(這也意味着你不必克隆那些大的.jar文件),但如果需要歷史記錄,你可以獲取歷史提交並使用git replace將它們無縫地拼接回來。

請參閱Scott Chacon的優秀博客文章 ,了解詳細解釋和演練。

這種方法的優點:

  • 歷史未被修改。 如果你需要回到一個較舊的提交,完成它的大.jars和一切,你仍然可以。
  • 如果您不需要查看舊的歷史記錄,那么本地克隆的大小很好而且很小,而且您制作的任何新克隆都不需要下載大量無用的數據。

這種方法的缺點:

  • 默認情況下,完整的歷史記錄不可用 - 用戶需要跳過一些環節來獲取歷史記錄。
  • 如果您確實需要經常訪問歷史記錄,那么無論如何您最終都會下載膨脹的提交。
  • 這種方法仍然存在一些與重寫歷史相同的問題。 例如,如果您的新存儲庫如下所示:

     * modify bar (master) | * modify foo <--replace--> * modify foo (historical/master) | | * instructions * remove all of the big .jar files | * add another jar | * modify a jar | 

    並且有人在他們合並的歷史分支中有一個舊分支:

     * merge feature xyz into master (master) |\\__________________________ | \\ * modify bar * add feature xyz | | * modify foo <--replace--> * modify foo (historical/master) | | * instructions * remove all of the big .jar files | * add another jar | * modify a jar | 

    然后,大的歷史提交將重新出現在您的主存儲庫中,並且您將回到您開始的位置。 請注意,這並不比重寫歷史記錄更糟糕 - 有人可能會在預重寫提交中意外合並。

    這可以通過在共享存儲庫中添加update掛鈎來減輕任何將重新引入歷史根提交的推送來緩解。

不,這是不可能的 - 你將不得不重寫歷史。 但是這里有一些指示:

  • 正如VonC所提到的 :如果它適合你的場景,使用BFG-repo清理器 - 它比git filter-branch更容易使用。
  • 你不需要再次克隆! 只需運行這些命令而不是git pull ,你就可以了(用你的遠程和分支替換originmaster ):

     git fetch origin git reset --hard origin/master 

    但請注意,與git pull不同,您將丟失尚未推送到服務器的所有本地更改。

  • 如果你(或你團隊中的其他人)完全理解git如何看待歷史,以及git pullgit mergegit rebase (以及git rebase --onto )這樣做,它git rebase --onto幫助。 然后讓每個人都參與一個關於如何處理這種重寫情況的快速培訓(5-10分鍾就足夠了,基本的注意事項和注意事項)。
  • 請注意, git filter-branch本身不會造成任何傷害,但會導致許多標准工作流程造成傷害。 如果人們沒有采取相應行動並合並舊歷史,如果您沒有及時發現,可能只需要重新編寫歷史記錄。
  • 您可以通過在服務器上寫入(5行)適當的更新掛鈎來阻止人們合並(更准確地推送)舊歷史記錄。 只需檢查推頭的歷史記錄是否包含特定的舊提交。

我不知道一個可以避免重寫歷史的解決方案。

在這種情況下,使用BFG-repo清潔工具清潔rpeo是最簡單的解決方案( git filter-branch更容易)。

老實說,我想不出辦法做到這一點。 如果你考慮Git“承諾”你作為一個用戶,關於數據完整性,我想不出你可以從存儲庫中刪除文件並保持相同的哈希的方法。 換句話說,如果你問的是可能的,那么Git的可靠性會低得多......

暫無
暫無

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

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