2013-07-04 77 views
17

我们有多个git存储库,由于二进制测试文件和java文件的历史包含,这些存储库已经发展到难以管理的大小。是否可以修改.git存储库而不重写历史记录?

我们即将完成这些存储库的练习,将它们重新克隆到它们使用的任何地方(从每次数十次到数百次,具体取决于回购)并给出problems with rewriting history我想知道是否存在可能是其他解决方案。

理想情况下,我想在不重写每个存储库的历史记录的情况下将问题文件外部化。理论上这应该是可能的,因为你正在检出相同的文件,具有相同的大小和相同的哈希,只是从不同的地方(远程而不是本地对象存储)获取它们。唉,迄今为止我找到的潜在解决方案似乎都不允许我这样做。

git-annex开始,我能找到的最接近解决我的问题是How to retroactively annex a file already in a git repo,但与刚刚删除的大文件,这需要历史被重新写入原来git add转换为git annex add

从那里开始,我开始考虑在what git-annex is not上列出的其他项目,所以我检查了git-bigfiles,git-mediagit-fat。不幸的是,我们不能使用git-bigfiles分支git因为我们是一个Eclipse 商店并且使用gitEGit的混合物。它看起来并不像混帐媒体混帐脂肪可以做我想做决定,因为当你可以与外部等同替换现有的大文件,你仍然需要改写历史,以去除大已经提交的文件。

那么,是否可以在不改写历史记录的情况下减少.git存储库,还是应该回到使用git filter-branch以及整个重新部署的计划?


顺便说一句,相信这应该是可能的,但可能是依赖于相同的限制那些git目前shallow clone实现。

的Git已经支持相同的blob多个可能的位置,因为任何给定的斑点可能是在loose object store.git/objects),或在一个pack file(git的/对象),所以理论上你只需要像在git-annex而钩在那个级别而不是更高的级别(即如果你愿意,可以有一个下载点的概念远程blob)。不幸的是,我找不到任何人已经实施甚至提出这样的建议。

+0

据我可以告诉你问如何在不重写历史的情况下重写历史。 – alternative

+0

@alternative不完全,我问是否有一种方法可以在不重写历史记录的情况下减少资源库*。目前看起来像使用浅层克隆可能是唯一的方法,但是这些限制可能不适用于我们的工作流程,即使这样做,他们也只会减少本地(克隆)回购站点,而不是远程裸站回购。 –

+0

“瘦”仓库的唯一方法是删除你瘦身的内容 - 因此,重写(这就是为什么每个答案都说这是不可能的)。只要你做得正确,就不会有重写历史的问题。是的,浅层克隆只会影响本地存储库。 – alternative

回答

8

的排序。您可以使用Git's replace feature预留庞大的历史记录,以便只在需要时才下载。它就像一个浅层克隆,但没有浅层克隆的限制。

这个想法是通过创建一个新的根提交重新启动一个分支,然后樱桃选择旧分支的提示提交。通常你会以这种方式失去所有的历史记录(这也意味着你不需要克隆那些大的文件),但是如果需要历史记录,你可以获取历史提交并使用git replace将它们无缝地重新拼接。

请参阅Scott Chacon's excellent blog post了解详细的解释和步骤。这种方法的

优点:

  • 历史不会被修改。如果你需要返回到一个较大的提交完成,它的大.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挂钩来缓解,以拒绝任何将重新引入历史根提交的推送。

+0

哇,谢谢理查德,这看起来可能就是我一直在寻找的东西。我会在下周看到它是否能够正常工作,如果有的话,还会有一个勾号来到你的方向... –

+0

啊,我明白了,所以这个例子重写了*最近提交的历史*以删除大的历史提交,而不需要重写这些*历史提交的历史*,但是如果需要的话,可以使用'git replace'让您在以后提交*历史提交*。所以,这并不是我所追求的,但我会更多地考虑如何使用它来解决我的问题。 –

+0

当我们从我们旧'svn'回购库中创建'git'回收库时,我确实希望知道这件事。我们可以将我们整个'svn'回购库保存在一组历史性的''svn''中,而不必从'svn'开始一个新纪元或者开始'git'回购, git' repos,然后使用'git replace'在需要时将其恢复。事实上,我想知道我们是否还能回去添加回顾性的'git replace'目标。有趣,非常有趣... –

4

我不知道会避免重写历史的解决方案。

在这种情况下,清洁与像BFG- repo cleaner的工具rpeo是最简单的解决方案(即更容易git filter-branch)。

2

我真的不能想办法做到这一点。如果你考虑Git“承诺”你作为一个用户,关于数据完整性,我想不出你能从存储库中删除一个文件并保持相同散列的方式。换句话说,如果你问的是可能的话,那么Git的可靠性就会低很多......

8

不,这是不可能的 - 你将不得不重写历史。但这里有一些指针是:

  • As VonC mentioned:如果它适合你的情况下,使用BFG- repo cleaner - 这是一个更容易比git filter-branch使用。
  • 你不需要再次克隆!只要运行这些命令,而不是git pull,你将被罚款(与您的远程和分支取代originmaster):

    git fetch origin 
    git reset --hard origin/master 
    

    但要注意,不像git pull,你将失去所有未推到了当地的变化服务器呢。

  • 它帮助很多,如果你(或别人在你的团队)充分了解混帐如何看待历史,什么git pullgit mergegit rebase(也为git rebase --onto)做的。然后让每个人都参与到如何处理这种重写情况的快速培训中(5-10分钟就足够了,这是基本的做法和不该做的事情)。
  • 请注意,git filter-branch本身不会造成任何伤害,但会导致大量标准工作流程造成伤害。如果人们没有采取相应的行动并合并旧的历史,如果你没有及时注意到,你可能只需要重写历史。
  • 您可以通过在服务器上写入(5行)适当的update hook来防止人们合并(更精确地推送)旧的历史记录。只要检查推动头的历史记录是否包含特定的旧提交。
+0

感谢Chronial。使用* not *重新克隆的唯一真正问题是不得不'重置'在本地使用的每个分支(以摆脱所有本地refs到已过时的分支)并运行'git gc --prune = now --aggressive'实际上缩小了回购。如果你这样做,回购*不*缩水,那么你知道你错过了某处的参考。重新克隆不需要所有这些步骤(我们使用'buckminster'部署我们20个左右的'git' repos,因此重新克隆*所有内容对我们来说都很容易)。可悲的是,我们还使用gitolite来托管我们的'git' repos,它保留'update'钩子以供它自己使用。 –

+0

难道你不能以同样的方式扩展'update'钩子吗? – Chronial

+0

我不知道* gitolite *,但[钩子和gitolite](http://gitolite.com/gitolite/cust.html#hooks)说*您可以安装以下任何钩子:(所有回购)gitolite储备'update'钩子*,所以我必须等到我们的gitolite专家回来告诉我是否有办法解决这个问题。 –

相关问题