树包含重复的文件条目

时间:2012-11-01 14:03:39

标签: git object duplicates

在我们托管的一些问题之后,我们决定将我们的Git存储库移动到GitHub。所以我克隆了存储库并尝试将其推送到GitHub。但是,我偶然发现了一些我们以前从未遇到过的错误:

 C:\repositories\appName [master]> git push -u origin master
 Counting objects: 54483, done.
 Delta compression using up to 2 threads.
 Compressing objects: 100% (18430/18430), done.
 error: object 9eac1e639bbf890f4d1d52e04c32d72d5c29082e:contains duplicate file entries
 fatal: Error in object
 fatal: sha1 file '<stdout>' write error: Invalid arguments
 error: failed to push some refs to 'ssh://git@github.com/User/Project.git'

当我运行fsck时:

C:\repositories\appName [master]> git fsck --full
Checking object directories: 100% (256/256), done.
error in tree 0db4b3eb0e0b9e3ee41842229cdc058f01cd9c32: contains duplicate file entries
error in tree 9eac1e639bbf890f4d1d52e04c32d72d5c29082e: contains duplicate file entries
error in tree 4ff6e424d9dd2e3a004d62c56f99e798ac27e7bf: contains duplicate file entries
Checking objects: 100% (54581/54581), done.

当我使用错误的SHA1运行ls-tree时:

C:\repositories\appName [master]> git ls-tree 9eac1e639bbf890f4d1d52e04c32d72d5c29082e
160000 commit 5de114491070a2ccc58ae8c8ac4bef61522e0667  MenuBundle
040000 tree 9965718812098a5680e74d3abbfa26f527d4e1fb    MenuBundle

我尝试了StackOverflow question已经给出的所有答案,但没有取得任何成功。有什么方法可以阻止这个存储库及其历史注定失败吗?

3 个答案:

答案 0 :(得分:8)

方法1。

首先执行git fsck

$ git fsck --full
error in tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29: contains duplicate file entries

如果这不能解决问题,那你就麻烦了。 您可以忽略该问题,从备份还原存储库,或将文件移动到新存储库中。如果您在将repo推送到github时遇到问题,请尝试将存储库更改为其他存储库或检查:Can't push to GitHub error: pack-objects died of signal 13Can't push new git repository to github


以下方法仅适用于高级git用户。请在开始之前进行备份。以下步骤无法保证解决方案,并且可能会使情况变得更糟,因此为了您自己的风险或教育目的而这样做。


方法2。

使用git ls-tree识别重复文件。

$ git read-tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29 # Just a hint.
$ git ls-tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29 # Try also with: --full-tree -rt -l
160000 commit def08273a99cc8d965a20a8946f02f8b247eaa66  commerce_coupon_per_user
100644 blob 89a5293b512e28ffbaac1d66dfa1428d5ae65ce0    commerce_coupon_per_user
100644 blob 2f527480ce0009dda7766647e36f5e71dc48213b    commerce_coupon_per_user
100644 blob dfdd2a0b740f8cd681a6e7aa0a65a0691d7e6059    commerce_coupon_per_user
100644 blob 45886c0eda2ef57f92f962670fad331e80658b16    commerce_coupon_per_user
100644 blob 9f81b5ca62ed86c1a2363a46e1e68da1c7b452ee    commerce_coupon_per_user

如您所见,它包含重复的文件条目(commerce_coupon_per_user)!

$ git show bb81a5af7e9203f36c3201f2736fca77ab7c8f29
tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29

commerce_coupon_per_user
commerce_coupon_per_user
commerce_coupon_per_user
commerce_coupon_per_user
commerce_coupon_per_user
commerce_coupon_per_user

同样,您可以看到重复的文件条目(commerce_coupon_per_user)!

您可以尝试对每个列出的blob使用git show,并检查每个文件的内容。

然后继续在不同的git克隆上运行ls-tree用于该无效的ls-tree对象,以查看是否可以跟踪有效对象,或者是否所有对象都已损坏。

git ls-tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29

If you found the valid object containing non-duplicated file entries, save it into the file and re-create by using `git mktree` and `git replace`, e.g.

remote$ git ls-tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29 > working_tree.txt
$ cat working_tree.txt | git mktree
NEWTREEbb81a5af7e9203f36c3201f2736fca77ab7c8f29
$ git replace bb81a5af7e9203f36c3201f2736fca77ab7c8f29 NEWTREE4b825dc642cb6eb9a060e54bf8d69288fbee4904

如果这不会有帮助,您可以通过以下方式撤消更改:

$ git replace -d NEWTREE4b825dc642cb6eb9a060e54bf8d69288fbee4904

方法3。

当您知道哪个文件/目录条目重复时,您可以尝试删除该文件并在以后重新创建它。例如:

$ find . -name commerce_coupon_per_user # Find the duplicate entry.
$ git rm --cached `find . -name commerce_coupon_per_user` # Add -r for the dir.
$ git commit -m'Removing invalid git entry for now.' -a
$ git gc --aggressive --prune # Deletes loose objects! Please do the backup before just in case.

了解更多:


方法4。

检查您的提交是否有无效条目。

让我们再次检查我们的树。

$ git ls-tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29 --full-tree -rt -l
160000 commit def08273a99cc8d965a20a8946f02f8b247eaa66  commerce_coupon_per_user
100644 blob 89a5293b512e28ffbaac1d66dfa1428d5ae65ce0     270    commerce_coupon_per_user
....
$ git show def08273a99cc8d965a20a8946f02f8b247eaa66
fatal: bad object def08273a99cc8d965a20a8946f02f8b247eaa66
$ git cat-file commit def08273a99cc8d965a20a8946f02f8b247eaa66
fatal: git cat-file def08273a99cc8d965a20a8946f02f8b247eaa66: bad file

以上提交似乎无效,让我们使用以下命令之一扫描我们的git日志以查看此提交:

$ git log -C3 --patch | less +/def08273a99cc8d965a20a8946f02f8b247eaa66
$ git log -C3 --patch | grep -C10 def08273a99cc8d965a20a8946f02f8b247eaa66

commit 505446e02c68fe306aec5b0dc2ccb75b274c75a9
Date:   Thu Jul 3 16:06:25 2014 +0100

    Added dir.

new file mode 160000
index 0000000..def0827
--- /dev/null
+++ b/sandbox/commerce_coupon_per_user
@@ -0,0 +1 @@
+Subproject commit def08273a99cc8d965a20a8946f02f8b247eaa66

在这种特殊情况下,我们的提交指向坏对象,因为它是作为git子项目的一部分提交的,它不再存在(检查git submodule status)。

您可以从ls-tree中排除该无效对象,并在没有此错误对象的情况下重新创建树,例如:

$ git ls-tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29 | grep -v def08273a99cc8d965a20a8946f02f8b247eaa66 | git mktree
b964946faf34468cb2ee8e2f24794ae1da1ebe20

$ git replace bb81a5af7e9203f36c3201f2736fca77ab7c8f29 b964946faf34468cb2ee8e2f24794ae1da1ebe20

$ git ls-tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29 # Re-test.
$ git fsck -full

注意:旧对象仍应抛出重复的文件条目,但如果您现在在新树中重复,则需要从该树中删除更多内容。所以:

$ git replace # List replace objects.
bb81a5af7e9203f36c3201f2736fca77ab7c8f29
$ git replace -d bb81a5af7e9203f36c3201f2736fca77ab7c8f29 # Remove previously replaced object.

现在让我们尝试从该树中删除所有提交和blob,然后再次替换:

$ git ls-tree bb81a5af7e9203f36c3201f2736fca77ab7c8f29 | grep -ve commit -e blob | git mktree
4b825dc642cb6eb9a060e54bf8d69288fbee4904
$ git replace bb81a5af7e9203f36c3201f2736fca77ab7c8f29 4b825dc642cb6eb9a060e54bf8d69288fbee4904

现在您有无效条目的空树。

$ git status # Check if everything is fine.
$ git show 4b825dc642cb6eb9a060e54bf8d69288fbee4904 # Re-check
$ git ls-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 --full-tree # Re-check

如果您对舞台有一些奇怪的更改,请通过以下方式重置您的存储库:

$ git reset HEAD --hard

如果您遇到以下错误:

HEAD is now at 5a4ed8e Some message at bb81a5af7e9203f36c3201f2736fca77ab7c8f29

执行rebase并删除该提交(将pick更改为edit):

$ git rebase -i
$ git commit -m'Fixed invalid commit.' -a
rebase in progress; onto 691f725
You are currently editing a commit while rebasing branch 'dev' on '691f725'.
$ git rebase --continue
$ git reset --hard
$ git reset HEAD --hard
$ git reset origin/master --hard

方法5。

尝试删除并压缩包含无效对象的无效提交。

$ git rebase -i HEAD~100 # 100 commits behind HEAD, increase if required.

了解详情:Git Tools - Rewriting HistoryHow do I rebase while skipping a particular commit?


方法6。

通过以下方法识别无效的git对象以进行手动删除:

  • 对于未压缩的对象(*请删除前两个字符,因为git将其用于目录名称):

    $ find . -name 81a5af7e9203f36c3201f2736fca77ab7c8f29
    
  • 用于压缩对象

    $ find . -name \*.idx -exec cat {} \; | git show-index | grep bb81a5af7e9203f36c3201f2736fca77ab7c8f29
    # Then you need to find the file manually.
    $ git unpack-objects $FILE # Expand the particular file.
    $ git unpack-objects < .git/objects/pack/pack-*.pack # Expand all.
    

请参阅:How to unpack all objects of a git repository?


相关:

答案 1 :(得分:2)

注意:Git 2.1将为git replace添加两个选项,这在修改git仓库中的损坏条目时非常有用:

  

以交互方式编辑对象的内容。 <object>的现有内容被打印到临时文件中,在文件上启动编辑器,并解析结果以创建与<object>相同类型的新对象。
  然后创建替换引用以用新创建的对象替换<object>   See git-var有关如何选择编辑器的详细信息。

commit 2deda62 Jeff King (peff)

替换:为--edit

添加--raw模式
  

git replace --edit”的目的之一是帮助用户修复格式错误或损坏的对象。
  通常我们用“ls-tree”打印树,这比原始二进制数据更容易使用。

然而,某些形式的腐败破坏了树木行走者,在这种情况下,我们的漂亮打印失败,使“--edit”对用户无用。

  

此补丁引入了“--raw”选项,可让您在这些实例中编辑二进制数据。

知道如何使用Jeff调试Git(如in this case),看到这个选项我并不感到惊讶。

答案 2 :(得分:1)

我遇到的唯一解决方案是使用git-replace和git-mktree。它不是世界上最简单的解决方案,但确实有效。

请参阅此链接以获取参考指南。

git tree contains duplicate file entries