如何删除 Git 树中具有 null sha1 的条目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24183847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to remove an entry with null sha1 in a Git tree
提问by gizmo
I have inherited of a git repository with a null sha1 for a commit entry in a tree, preventing FishEye to index the repository.
我继承了一个 git 存储库,其中一个空 sha1 用于树中的提交条目,阻止 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.
Looking for the given tree give me the following result:
寻找给定的树给我以下结果:
$ 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
Looking in the history, I've found that SomeDirectory
was initially a git submodule and that the commit that seems to cause the issue is the one that removed both the .gitmodules
and SomeDirectory
.
Now, there is a real directory called SomeDirectory
at the exact same place where the culprit was.
I though I could still try to fix run a git filter-branch
to see what I would end up, but it does not work:
展望历史,我发现,SomeDirectory
最初是一个混帐子模块,并且提交似乎导致问题是一个移除了.gitmodules
和SomeDirectory
。现在,SomeDirectory
在罪魁祸首所在的完全相同的地方有一个真实的目录。
我虽然仍然可以尝试修复 run agit 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]
What am I supposed to try next, knowing that there is no backup that I'm aware of prior to the commit that causes the issue.
我接下来应该尝试什么,知道在导致问题的提交之前没有我知道的备份。
回答by
The message you get suggests that there was only a single tree with a bad submodule. In that case, there is very little you have to clean up. You can create a new fixed tree that doesn't have this problem:
您收到的消息表明只有一棵树带有坏子模块。在这种情况下,您几乎不需要清理。您可以创建一个没有此问题的新固定树:
$ git ls-tree db22a67df70dc4ff90ec4cd666da91e9c2cb0d9 | > sed -e '/0\{40\}/d' | > git mktree (new tree SHA1 here)
Your question shows the git ls-tree
output already. The sed
removes the line with the bad submodule, and git mktree
creates a new tree object from the result.
您的问题已显示git ls-tree
输出。在sed
删除与坏的子模块的线,并git mktree
根据结果创建一个新的树对象。
Once you have the fixed tree, you can create a fixed commit using this tree:
拥有固定树后,您可以使用此树创建固定提交:
$ 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
prints the problematic commit object in a textual form. It will start with tree db22a67df70dc4ff90ec4cd666da91e9c2cb0d9
, and continues with the rest of the commit info (parent, author, committer, commit message). The sed
replaces the tree
line's reference to the old tree by the new one. git hash-object -t commit -w --stdin
creates a new commit object from the result, writes it to the repository, and prints its ID.
git cat-file commit c571a3ec94e9f84471577bac41ac7375c729ef08
以文本形式打印有问题的提交对象。它将以 开头tree db22a67df70dc4ff90ec4cd666da91e9c2cb0d9
,并继续提交其余的提交信息(父、作者、提交者、提交消息)。将sed
取代tree
由新一行的参考老树。git hash-object -t commit -w --stdin
根据结果创建一个新的提交对象,将其写入存储库,并打印其 ID。
Once you have the fixed commit, you can use git replace
:
一旦你有固定的提交,你可以使用git replace
:
$ git replace c571a3ec94e9f84471577bac41ac7375c729ef08 (new commit SHA1 here)
This doesn't actually change anything yet, but tells Git that whenever it would read commit c571a3ec94e9f84471577bac41ac7375c729ef08
, it should read the new commit object instead.
这实际上还没有改变任何东西,但告诉 Git 每当它读取 commit 时c571a3ec94e9f84471577bac41ac7375c729ef08
,它应该读取新的 commit 对象。
And finally, use git filter-branch
to make it permanent. This goes through all commits, reads them, and writes them back. Ordinarily, without any options to modify the commits, this wouldn't have much effect, but because of the earlier git replace
, this causes all commits with c571a3ec94e9f84471577bac41ac7375c729ef08
as a parent to be re-written to refer to the new commit instead, all commits which refer to those re-written as well, etc.
最后,使用git filter-branch
使其永久化。这会遍历所有提交,读取它们并将它们写回。通常,如果没有任何选项来修改提交,这不会有太大影响,但是由于较早的git replace
,这会导致所有c571a3ec94e9f84471577bac41ac7375c729ef08
以父级为父的提交都被重写为引用新的提交,所有引用的提交那些重写的,等等。
回答by hlovdal
Maybe it will work with an interactive rebase to modify the commit that contains the troublesome SomeDirectory commit reference, e.g.
也许它将与交互式 rebase 一起使用来修改包含麻烦的 SomeDirectory 提交引用的提交,例如
$ 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