提问者:小点点

如何删除Git树中具有null sha1的条目


我继承了一个带有null sha1的git存储库,用于树中的提交条目,防止FishEye索引存储库。

$ git fsck
Checking object directoriies: 100%(256/256), done.
warning in tree db22a67df70dc4ff90ec4cd666da91e9c2cb0d9:
    contains entries pointing to null sha1
Checking objects: 100% (416532/416532), done.
Checking connectivity: 416532, done.

寻找给定的树给我以下结果:

$ git ls-tree db22a6
100644 blob e615f18b55a39f2719112ce209c2505dd92d8e75    .gitignore
100644 blob ac852f06c5a04420356c1d5efca44d9a864e78b0    .project
160000 commit 0000000000000000000000000000000000000000  SomeDirectory
100644 blob 631c17e28026261a2ccf6bc570842cf4af9f181c    GoDeploy.bat
100644 blob 40e992ab5c3868af2910135c3ac4610c3646e7f8    pom.xml

纵观历史,我发现的某个目录最初是一个git子模块,似乎导致问题的提交是删除了. gitmodule的某个目录。现在,有一个真正的目录叫做的某个目录在罪魁祸首所在的完全相同的地方。
我想我仍然可以尝试修复运行git filter-分支以查看我最终会得到什么,但它不起作用:

$ git filter-branch --force --index-filter \
$ 'git rm --cached --ignore-unmatch SomeDirectory' \
$ --prune-empty --tag-name-filter cat -- --all
[... striped out for clarity]
Rewrite c571a3ec94e9f84471577bac41ac7375c729ef08 (76/18522)error:
    cache enttry has null sha1: SomeDirectory
fatal: unable to write new index file
Could not initialize the index
[... striped out for clarity]

知道在导致问题的提交之前没有我知道的备份,我接下来应该尝试什么。


共3个答案

匿名用户

您收到的消息表明只有一棵树具有错误的子模块。在这种情况下,您只需清理很少。您可以创建一个没有此问题的新固定树:

$ git ls-tree db22a67df70dc4ff90ec4cd666da91e9c2cb0d9 |
> sed -e '/0\{40\}/d' |
> git mktree
(new tree SHA1 here)

您的问题已经显示了git ls-tree输出。sed删除了带有坏子模块的行,git mktree从结果创建了一个新的树对象。

拥有固定树后,您可以使用此树创建固定提交:

$ git cat-file commit c571a3ec94e9f84471577bac41ac7375c729ef08 |
> sed 's/db22a67df70dc4ff90ec4cd666da91e9c2cb0d9/(new tree SHA1 here)/' |
> git hash-object -t commit -w --stdin
(new commit SHA1 here)

git cat-file提交c571a3ec94e9f84471577Bac41ac7375c729ef08以文本形式打印有问题的提交对象。它将从tree db22a67df70dc4ff90ec4cd666da91e9c2cb0d9开始,并继续其余的提交信息(父、作者、提交者、提交消息)。sedtree行对旧树的引用替换为新树。git hash-object-t提交-w--stdin从结果创建一个新的提交对象,将其写入存储库,并打印其ID。

一旦你有了固定的提交,你可以使用git替换

$ git replace c571a3ec94e9f84471577bac41ac7375c729ef08 (new commit SHA1 here)

这实际上还没有改变任何事情,但告诉Git,每当它读取提交c571a3ec94e9f84471577Bac41ac7375c729ef08时,它应该读取新的提交对象。

最后,使用git filter-分支使其永久化。这会遍历所有提交,读取它们并写回它们。通常,如果没有任何修改提交的选项,这不会有太大的影响,但由于早期的git替换,这会导致所有以c571a3ec94e9f84471577Bac41ac7375c729ef08作为父级的提交都被重写以引用新的提交,所有引用那些重写的提交等等。

匿名用户

对于任何仍然有问题的人,我使用git-filter-repo解决了这个问题:

git filter-repo --path <folder> --invert-paths

filter-repo与filter-分支空sha1没有相同的问题,并且速度要快得多。

看这个答案/问题:https://stackoverflow.com/a/61544937/1827771

匿名用户

也许它将与交互式rebase一起使用,以修改包含麻烦的某个目录提交引用的提交,例如。

$ git branch backup_branch       # To be able to revert if not satisfied
$ git rebase -i db22a6^          # From parent to db22a6
...
# You then select Edit for commit db22a6 in the editor
...
$ git reset HEAD^             # Reset the commit db22a6 but not its changes
$ git status
...
# should list as modified: .gitignore .project SomeDirectory GoDeploy.bat pom.xml
...
$ git checkout SomeDirectory     # Cancel the troublesome change
$ git add .gitignore .project GoDeploy.bat pom.xml
$ git commit -m "your commit message"
$ git rebase --continue