首页 > 解决方案 > 如何处理 .gitmodules 历史记录中的错误?

问题描述

当我尝试将一些 repo 推送到新服务器时出现错误:

$ git push -f research master
Enumerating objects: 13060, done.
Counting objects: 100% (13060/13060), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3397/3397), done.
Writing objects: 100% (13060/13060), 5.59 MiB | 364.00 KiB/s, done.
Total 13060 (delta 9516), reused 13060 (delta 9516)
remote: Resolving deltas: 100% (9516/9516), done.
remote: error: bad config line 14 in blob .gitmodules
remote: error: object 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb: gitmodulesParse: could not parse gitmodules blob
remote: fatal: fsck error in pack objects
error: remote unpack failed: index-pack abnormal exit
To gitlab.research.com:proj/repo.git
 ! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'git@gitlab.research.com:proj/repo.git'
$ 

git fsck奇怪的是,当我在本地运行时,我得到了同样的错误:

$ git fsck
Checking object directories: 100% (256/256), done.
warning in blob 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb: gitmodulesParse: could not parse gitmodules blob
Checking objects: 100% (13060/13060), done.
$ 

原来文件中的“第 14 行”.gitmodules不在文件的当前版本中,它只有 11 行长。问题的结果是因为.gitmodules提交的版本存在冲突。

我可以删除 blob 并将其推送到新的存储库,还是存在我无法轻松解决的深层问题?

编辑 - 新信息!

鉴于@torek 在下面的出色帖子,以及Which commit has this blob?(第一个脚本有效,但第二个没有),我能够找到有问题的提交:

$ ~/.bin/git-find-object 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb
06407fd merged changes from master and stats

我的 git repo 只有一个分支可见:

$ git branch -v
* master e8ff018 minor

我可以检查有问题的提交:

$ git checkout 06407fd
Checking out files: 100% (321/321), done.
fatal: bad config line 14 in file /home/xv32/gits/repo/.gitmodules

$

我直接编辑了.gitmodules文件,并删除了有问题的行:

<<<<<<< HEAD
        branch = ee
=======
>>>>>>> master

我做了一个git add .gitmodules

我做了一个:

$ git commit --amend -m 'fixed conflict in .gitmodules'

天哪,它改变了很多东西。

然后我做了一个git状态:

$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   submodule1 (new commits)
        modified:   submodule2 (new commits)
        modified:   submodule3(new commits)

no changes added to commit (use "git add" and/or "git commit -a")

$

git fsck 不再报告问题:

$ git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (15206/15206), done.

但我仍然无法推送到远程仓库:

$ git push -f research master
Counting objects: 13245, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3395/3395), done.
Writing objects: 100% (13245/13245), 5.68 MiB | 2.81 MiB/s, done.
Total 13245 (delta 9746), reused 13180 (delta 9702)
remote: error: bad config line 14 in blob .gitmodules
remote: error: object 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb: gitmodulesParse: could not parse gitmodules blob
remote: fatal: fsck error in packed object
error: remote unpack failed: index-pack abnormal exit
To https://gitlab.research.com/repo/repo.git
 ! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'https://gitlab.research.com/censyn-sensitive/das_decennial.git'

$

此外,当我这样做时git --amend,一大堆重要的事情消失了,超出了对象中的坏线。

老实说,我不明白为什么我什至会收到错误,因为错误不在树的顶部。

标签: git

解决方案


我可以只删除blob吗...

不:有一个树对象T说“我应该有 blob 4f098d01fb9671a7f5ff5f617ef89b289a8ea9bb”。因此,您必须找到并处理它。树T由某个提交对象C引用。由于文件是.gitmodules,这可能是该提交的顶级树。您可能必须找到该提交,但是:

问题的结果是因为.gitmodules提交的版本存在冲突。

... 提交,或者可能只是几个提交中的第一个提交,它有一棵树,上面写着“我应该拥有 blob”。换句话说,您已经找到了有问题的提交。

现在的诀窍是用一个新的和改进的版本重写那个提交。新版本应该与原始版本几乎相同,只是它的提交.gitmodules(一个 blob)应该是正确的,而不是不正确的。

替换提交后,您必须替换该提交的一个或多个子项,因为子项/子项通过其哈希 ID 引用错误提交,而新的、更正的替换具有不同的哈希 ID。当然,一旦你替换了它们,你就必须替换它们的子节点,以此类推,直到任何后代分支提示提交。

理想情况下,您可以只使用git rebase来解决此问题(如phd 建议的那样)。不幸的是,你说:

...发生了冲突

这意味着第一个错误提交本身就是一个合并。您不能对合并进行变基:您必须改为构造一个新的、更正的合并。

这究竟有多难或多容易取决于很多事情,例如您对 Git 内部工作的熟悉程度以及错误合并的“下游”有多少提交。如果只有几个,您可能只想重复合并,这次没有错误,然后手动复制一两个剩余的提交。

假设错误的合并是 commit X,并且它的第一个父级是 commit P

...--o--P--X--1--2   <-- master (HEAD)
          /
...---o--o   <-- otherbranch

这里只有两个后续提交,所以你可以:

git checkout <hash-of-P>
git merge otherbranch

与上次相同的冲突也会发生,但这次您可以正确解决它们因此.gitmodules是正确的。然后:

git cherry-pick <hash-of-1>
git cherry-pick <hash-of-2>

将复制提交12在这个新的替换合并之上:

          ,-X'-1'-2'  <-- HEAD
         / /
...--o--P-/-X--1--2   <-- master
         | /
         |/
...---o--o   <-- otherbranch

其中X'1'2'是新的和改进的版本。(您可能必须在挑选其中任何一个12fixed时修复合并冲突,方法.gitmodules是采用更正的.gitmodules;或者 Git 可能会看到这两个更改导致相同的事情,并决定不存在冲突。)

然后,您可以强制使用名称master来标识提交1',之后您可以忘记 commits X12曾经存在过:

...--o--P--X'-1'-2'  <-- master (HEAD)
          /
...---o--o   <-- otherbranch

现在你可以了git push -f research master

备择方案

除了这种方法,您还可以:

  • git checkout坏的直接合并();git checkout hash-of-X
  • 编辑.gitmodules文件以修复它,以及git add结果;
  • 运行git commit --amend:这使得X'.

这可能至少更容易一些,因为您不必重复其余的合并。然后,您可以重复采摘樱桃。

如果在错误的合并“之后”有很多提交,而不是一次只挑选一个,您可以使用git rebase --onto大量复制它们。这仅在这一系列提交中没有合并时才有效。也就是说,上述类型的图表可以正常工作,但是:

                   3--4--5
                  /       \
...--o--P--X--1--2------6--7--8   <-- master (HEAD)
          /
...---o--o   <-- otherbranch

可能不会,因为 commit7是一个合并:git rebase将完全删除它并尝试在其顶部创建一个新X'1-2-3-4-5-6-8or 1-2-6-3-4-5-8。这可能没问题,具体取决于您的需求。

最新版本的 Git 有一个--rebase-merges标志,它将重新执行合并(同时复制其他提交 a la git cherry-pick)。您可以在这种情况下使用它。

或者,最后,您可以使用git replace与 结合使用git filter-branch。如果您有数以万计的“下游”提交和/或下游的许多分支和合并操作,这是最合适的。否则,您不妨坚持修复错误的合并,然后重新设置或挑选剩余的提交。


推荐阅读