重写分支上的历史记录后的Git repo大小

时间:2018-01-10 20:11:12

标签: git

由于过去人们添加了一些SQL转储,因此我的分支越来越大。它是800M,清理后只剩下90M。但是,我有一个用例,我必须回收:

回购A. Repo B(来自Repo A的叉子)。

当我清理Repo A的历史记录以删除该内容,然后将A合并到B时会发生什么。然后B会受到影响,因为从技术上讲,历史突然不同了吗?

或者处理这个问题的最佳方法是什么,因为在这种情况下回购会变得太大,当然这是一个非结束的故事。

我自己做的是测试,在这种情况下,B的文件大小保持不变。这意味着历史在A上发生了变化,但在这种情况下显然没有合并到B?用以下内容执行:

git merge remotea/develop开发op remote b

感谢您的反馈。欢迎提示

1 个答案:

答案 0 :(得分:1)

合并不会删除历史记录。具体做法是:

你从

开始
C -- D -- E -- F <--(develop)
在A和B中都是

。你在回购A中进行了一些清理。你没有说明你做了什么,但是假设你最终得到类似的东西

C -- E' -- F' <--(develop)
A中的

(我假设C未更改,因为否则您的合并尝试会被投诉,而您必须使用--allow-unrelated-histories选项。)

然后在B中,我们假设您只是运行git fetch。你有

C -- D -- E -- F <--(develop)
 \
  E' -- F' <--(remotea/develop)

现在如果你合并,我认为你会遇到很多冲突;但不管怎样,你可以解决这个问题。那意味着你有

C -- D -- E -- F -- M<--(develop)
 \                 /
  E' ----------- F' <--(remotea/develop)

并且您看到您只添加了新的历史记录,因此回购协议当然不会缩小。

如果它很简单,我想最简单的方法就是通过再次分叉来重新创建B.但是你有一个分叉的事实表明,一些变化可能只存在于B.也许你真的有

C -- D -- E -- X -- Y -- Z <--(develop)
 \
  E' -- F' <--(remotea/develop)

其中B尚未收到F(或F'),但它有自己的更改X .. Z

在这种情况下,清理回购B的难度要大得多,因为回购B的变化必须在某些时候被重新修改为修订后的历史。

例如,您可以尝试类似

的内容
git rebase --onto remotea/develop develop~2 develop

获取

C -- D -- E -- X -- Y -- Z
 \
  E' -- F' <--(remotea/develop)
          \
           X` -- Y` -- Z` <--(develop)

(或者你可以说--onto remotea/develop^然后合并,如果你想保留更像原始提交拓扑的东西)。但请注意,原始历史暂时仍然存在(尽管不可行)。它必须最终获得gc,或者你必须做更多的步骤来加快清理速度。 (因为你清理了回购A,我认为你已经了解它是如何工作的。)

这仍然过于简单化,因为您可能会有一个更复杂的历史记录,其中回购B的更改在回购A的更新之间混合。

  x -- x -- M -- x -- x -- M -- x -- x <--(develop)
 /         /              /         
C -- D -- E -- F -- G -- H 
 \
  E' -- F' -- G' -- H' -- I' -- J' <--(origina/develop)

此处,repo b最后一次从repo a获取更新,origina/develop位于H,但已合并。但现在重写后origina/develop有新的历史记录。< / p>

正如孩子们所说,你所拥有的是一团糟。当前develop通过多个路径到达&#34;坏&#34; /大型提交,并且与远程的合并基础一直在C。你可以做一系列的合并和重组。每个合并和每个rebase都可能产生冲突,特别是如果任何原始合并(当你从a更新b时)发生冲突,你将不得不重做这些决议。

git checkout develop~6
git checkout -b temp
git merge origina/develop~5

产量

C -- D -- E -- F -- G -- H 
|\         \              \
| x -- x -- M -- x -- x -- M -- x -- x <--(develop)
 \      \   
  E' --- M <--(temp)
   \
    F' -- G' -- H' -- I' -- J' <--(origina/develop)

然后

git checkout develop~3
git checkout -b temp2
git rebase --onto temp temp2~2
git branch -d temp
git merge origina/develop~2

产量

C -- D -- E -- F -- G -- H 
|\         \              \
| x -- x -- M -- x -- x -- M -- x -- x <--(develop)
 \      \   
  E' --- M -- x' -- x' -- M <--(temp2)
   \                     /
    F' ------ G' ----- H' -- I' -- J' <--(origina/develop)

最后

git rebase --onto temp2 develop~2 develop
git branch -d temp2

给你

C -- D -- E -- F -- G -- H 
|\         \              \
| x -- x -- M -- x -- x -- M -- x -- x
 \      \   
  E' --- M -- x' -- x' -- M -- x` -- x` <--(develop)
   \                     /
    F' ------ G' ----- H' -- I' -- J' <--(origina/develop)

与往常一样,原始历史仍然存在,但是一旦你得到它,gc&#39; d就变成

C ------ E' -- F' -- G' -- H' -- I' -- J' <--(origin/develop)
 \         \                \
  x -- x -- M -- x' -- x' -- M -- x' -- x' <--(develop)

但即使我对冲突解决方案的复杂性大都有所掩饰,你也可以看到这是很多工作。

另一种方法是独立清理b仓库,但这样可以提供类似

的东西
  x -- x -- M' -- x' -- x' -- M' -- x' -- x' <--(develop)
 /         /                 /         
C ------ E" -- F" -- G" -- H"
 \
  E' -- F' -- G' -- H' -- I' -- J' <--(origina/develop)

那么你必须向git解释从E'H'的所有内容都已在develop中解释,所以你可能会做类似的事情

git checkout develop
git merge -s ours origin/develop~2

获取

  x -- x -- M' -- x' -- x' -- M' - x' - x' - m <--(develop)
 /         /                 /              /
C ------ E" -- F" -- G" -- H"              /
 \                                        /
  E' --------- F' --------- G' -------- H' -- I' -- J' <--(origina/develop)

请注意,小写 - m非常&#34;非默认&#34;合并结果 - 它只保留TREE上已有的内容(master)。因为使用默认合并策略肯定会发生冲突,所以这不是最糟糕的事情。

无论如何,这种历史更为奇怪,但它更简单。除了它是基于完成两次整个清理练习(一次在回购A中,另一次在回购B中)。

故事的寓意是,摆脱这种情况的最好方法是不要陷入这种情况。