git fsck:duplicateEntries:包含重复的文件条目-无法推送到gitlab

时间:2019-05-28 14:06:39

标签: git gitlab

我们有一个很大的git存储库,我想将其推送到自托管的gitlab实例。

问题是gitlab遥控器不允许我推送我的仓库:

git push --mirror https://mygitlab/xy/myrepo.git

这会给我这个错误:

Enumerating objects: 1383567, done.
Counting objects: 100% (1383567/1383567), done.
Delta compression using up to 8 threads
Compressing objects: 100% (207614/207614), done.
remote: error: object c05ac7f76dcd3e8fb3b7faf7aab9b7a855647867: 
duplicateEntries: contains duplicate file entries
remote: fatal: fsck error in packed object    

所以我做了一个git fsck:

error in tree c05ac7f76dcd3e8fb3b7faf7aab9b7a855647867: duplicateEntries: contains duplicate file entries
error in tree 0d7286cedf43c65e1ce9f69b74baaf0ca2b73e2b: duplicateEntries: contains duplicate file entries
error in tree 7f14e6474400417d11dfd5eba89b8370c67aad3a: duplicateEntries: contains duplicate file entries

我接下来要做的是检查git ls-tree c05ac7f76dcd3e8fb3b7faf7aab9b7a855647867

100644 blob c233c88b192acfc20548d9d9f0c81c48c6a05a66    fileA.cs
100644 blob 5d6096cb75d27780cdf6da8a3b4d357515f004e0    fileB.cs
100644 blob 5d6096cb75d27780cdf6da8a3b4d357515f004e0    fileB.cs
100644 blob d2a4248bcda39c0dc3827b495f7751b7cc06c816    fileC.xaml

请注意,fileB.cs被显示两次,且具有相同的哈希值。我以为这就是问题所在,因为为什么文件在同一树中被两次使用相同的文件名和Blob哈希?

现在我用Google搜索了问题,但是找不到解决此问题的方法。 我发现一个看似不错的资源是:Tree contains duplicate file entries

但是,基本上可以归结为使用git replace并不能真正解决问题,因此git fsck仍然会打印错误并阻止我将其推送到远程。

然后有一个似乎可以完全删除文件的文件(但是我仍然需要该文件,但是只需要一次,在树中没有两次):https://stackoverflow.com/a/44672692/826244

还有其他解决方法吗?我的意思是说真的应该可以修复,以便git fsck不会抛出任何错误,对吗?我知道在损坏的提交之后,我将需要重写整个历史记录。我什至找不到找到指向特定树的提交的方法,否则我也许可以使用rebase并修补损坏的提交或其他内容。任何帮助将不胜感激!

更新: 非常确定我知道要做什么,但还不知道如何要这样做:

  1. 从旧树创建新树对象,但已通过git mktree更正<-完成
  2. 创建一个新的提交,该提交与引用坏树的旧提交相同,但是使用新固定的树<-困难,我无法轻松地将提交提交给该树,我当前的解决方案运行了一个小时或更长时间,我一旦找到,就不知道如何创建修改后的提交
  3. 运行git filter-branch -- --all <-应该坚持提交的替换

可悲的是,我不能只在坏树上使用git replace --edit然后运行git filter-branch -- --all,因为filter-branch似乎仅适用于提交,而忽略树替换...

4 个答案:

答案 0 :(得分:1)

您可以尝试运行git fast-export将存储库导出到数据文件中,然后运行git fast-import将数据文件重新导入到新存储库中。 Git将在快速导入过程中删除所有重复的条目,这将解决您的问题。

请注意,在导出时,可能需要通过将适当的参数传递给git fast-export来决定如何处理带符号的标签;由于您正在重写历史记录,因此您可能希望传递--signed-tags=strip

答案 1 :(得分:1)

最终的解决方案是编写一个解决此问题的工具。

第一步是git unpack-objects所有packfiles。 然后,我必须通过读取所有引用,然后回溯历史检查所有树来确定指向具有重复项的树条目的提交。 在拥有用于该工具的工具之后,现在不难重写这些提交的树,然后再重写所有提交。之后,我必须更新更改的引用。这是我彻底测试结果的时刻,因为还没有丢失任何东西。 最后,git reflog expire --expire=now --all && git gc --prune=now --aggressive重新编写了包装,并删除了所有不再可访问的松散对象。

有时间的时候,我会将源代码上传到github,因为它的性能非常好,并且可能是类似问题的模板。它仅在3.7GB的存储库(解压缩后约20GB)上运行了几分钟。到目前为止,我还实现了从packfile文件中读取数据,因此不再需要解压缩任何文件(这会花费大量的时间和空间)。

更新:我在源代码上做了更多的工作,它现在表现得非常好,甚至比bfg删除单个文件要好(尚无选项开关)。 源代码可在此处获得:https://github.com/TimHeinrich/GitRewrite 请注意,这仅针对单个存储库进行了测试,并且仅在核心i7上的Windows下进行了测试。它极不可能在linux或任何其他处理器体系结构上运行

答案 2 :(得分:0)

您可以删除相关的引用并使它的对象失效。

为了找到相关的参考,请运行:

$ git log --all --format=raw --raw -t --no-abbrev

并搜索更改符号,然后在$ git show-refs

中找到它

接下来,对于每个持有不良对象的裁判,都要这样做:

$ git update-ref -d refs/changes/xx/xxxxxx/x

最后使对象过期并运行fsck,应该将其修复。

$ git reflog expire --expire=now --all
$ git gc --prune=now --aggressive
$ git fsck

答案 3 :(得分:0)

我发现与gitlab没有fsck.skipList有关的问题,我认为该解决方案可能适用:

为了推送到gitlab中的新项目,该家伙在创建该GitLab项目时使用了导入功能,并直接从他的其他仓库中导入了该项目。

注意:它没有在本地修复它,但允许导入它,也许以这种方式导入已经远程生成了一个干净的分支。