我们有一个很大的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并修补损坏的提交或其他内容。任何帮助将不胜感激!
更新: 非常确定我知道要做什么,但还不知道如何要这样做:
git mktree
更正<-完成git filter-branch -- --all
<-应该坚持提交的替换可悲的是,我不能只在坏树上使用git replace --edit
然后运行git filter-branch -- --all
,因为filter-branch
似乎仅适用于提交,而忽略树替换...
答案 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项目时使用了导入功能,并直接从他的其他仓库中导入了该项目。
注意:它没有在本地修复它,但允许导入它,也许以这种方式导入已经远程生成了一个干净的分支。