【问题标题】:git fsck: duplicateEntries: contains duplicate file entries - cannot push to gitlabgit fsck:duplicateEntries:包含重复的文件条目 - 无法推送到 gitlab
【发布时间】:2019-05-28 14:06:38
【问题描述】:

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

问题是 gitlab 远程不允许我推送我的 repo:

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 哈希?

现在我用谷歌搜索了这个问题,但找不到解决这个问题的方法。 我发现的一个看似不错的资源是: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 似乎只适用于提交,但忽略了树替换...

【问题讨论】:

  • 您的(客户端)和 GitLab 端(服务器,除非自托管也意味着自托管在同一台计算机上)有什么操作系统和 Git 版本?
  • Windows 上的 git 版本 2.21.0,Linux 上的 gitlab 11.9,不确定是哪一个。但是这个问题在 windows 和 linux 上是可以重现的,用git clone --mirror 检出,然后运行git fsck
  • 显然,存储库本身已损坏。
  • 是的,如果可能的话,我想解决这个问题
  • 我在你的回答中没有看到stackoverflow.com/a/24868719/6309 中提到的git show <bad_tree>:这至少会显示重复的条目。

标签: git gitlab


【解决方案1】:

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

请注意,当您通过将适当的参数传递给git fast-export 进行导出时,您可能必须决定如何处理签名标签等;因为你正在重写历史,你可能想通过--signed-tags=strip

【讨论】:

  • 我目前正在尝试这个。但是现在它已经运行了大约 4 个小时,并且目标存储库变得越来越大,所以我需要在之后运行重新打包。完成后我会更新它是否有效。
  • 它重写了所有提交,存储库变得太大,即使在重新打包后也花了太长时间:/
  • 运行导入似乎需要很长时间。
  • 这是一个缓慢的过程。
【解决方案2】:

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

第一步是 git unpack-objects 所有打包文件。 然后,我必须通过读取所有 ref 并返回历史记录检查所有树来识别指向具有重复项的树条目的提交。 在我有了工具之后,现在重写这些提交的树并在此之后重写所有提交并不难。之后我必须更新更改的参考。这是我彻底测试结果的那一刻,因为什么都没有丢失。 最后,git reflog expire --expire=now --all && git gc --prune=now --aggressive 重写了包并删除了所有无法再访问的松散对象。

当我有时间时,我会将源代码上传到 github,因为它的性能非常好,可以作为类似问题的模板。它只在 3.7GB 的存储库上运行了几分钟(大约 20GB 未打包)。现在我还实现了从包文件中读取,所以不再需要解包任何东西(这需要大量的时间和空间)。

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

【讨论】:

  • 赞成,但不要忘记在 GitHub 上发布后使用工具链接更新此答案。或者我们会有另一种“保证金”的情况:explainxkcd.com/wiki/index.php/1381:_Margin
  • 添加了源链接
  • 完美,谢谢!应该可以将您的工具交叉编译到其他平台。
  • 是的,我只是不确定我是否对其他平台进行了正确的字节顺序检查,以及我是否在任何地方都使用了与平台无关的路径分隔符
【解决方案3】:

您可以删除相关的 ref 并使其对象过期。

为了找到相关的refs运行:

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

并搜索更改sha,然后在$ git show-refs中找到它

接下来,对于每个持有坏对象的 ref:

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

最后使对象过期并运行fsck,应该是固定的。

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

【讨论】:

  • 我仍然需要所有的 refs 和它的对象。我只需要更改对象,使它们不再无效。
  • @Tim,您是否尝试改用 rebase 命令? git rebase -fr (git-scm.com/docs/git-rebase)
  • 这个想法是从以前的提交创建一个分支,然后使用 -fr 选项从源分支重新设置它。
【解决方案4】:

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

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

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

【讨论】:

    猜你喜欢
    • 2018-02-19
    • 2014-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-22
    • 2020-03-04
    • 1970-01-01
    相关资源
    最近更新 更多