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

giz*_*zmo 8 git git-filter-branch atlassian-fisheye

我为树中的提交条目继承了一个带有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.
Run Code Online (Sandbox Code Playgroud)

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

$ 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
Run Code Online (Sandbox Code Playgroud)

回顾一下历史,我发现这SomeDirectory最初是一个git子模块,而且似乎导致问题的提交就是删除了.gitmodulesSomeDirectory.现在,有一个真正的目录SomeDirectory在罪魁祸首的完全相同的地方被调用.
我虽然我仍然可以尝试修复运行a git filter-branch以查看我最终会得到什么,但它不起作用:

$ 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]
Run Code Online (Sandbox Code Playgroud)

我应该尝试下一步,知道在导致问题的提交之前没有我知道的备份.

小智 14

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

$ 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 commit c571a3ec94e9f84471577bac41ac7375c729ef08以文本形式打印有问题的提交对象.它将从tree db22a67df70dc4ff90ec4cd666da91e9c2cb0d9其余的提交信息(父,作者,提交者,提交消息)开始并继续.用新的sed替换tree行对旧树的引用.git hash-object -t commit -w --stdin从结果创建新的提交对象,将其写入存储库,并打印其ID.

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

$ git replace c571a3ec94e9f84471577bac41ac7375c729ef08 (new commit SHA1 here)

这实际上并没有改变任何东西,但告诉Git无论什么时候它会读取提交c571a3ec94e9f84471577bac41ac7375c729ef08,它应该读取新的提交对象.

最后,用git filter-branch它来使它永久化.这将通过所有提交,读取它们并将它们写回.通常,没有任何修改提交的选项,这不会产生太大影响,但由于前面的git replace原因,这会导致所有提交c571a3ec94e9f84471577bac41ac7375c729ef08作为父项的提交被重写以引用新提交,所有提交引用那些重写,等等

  • 如果这也能解释这些命令正在做什么,那就太棒了。每次我遇到 git 问题并最终陷入 SO 时,我都会[感觉像这样](https://xkcd.com/1597/) (2认同)
  • @AnderBiguri 足够公平,这有帮助吗? (2认同)