问题描述
问题
我有两个代码库“REPO A”和“REPO B”,它们属于同一个项目。事实上,REPO B 是 REPO A 的延续,因此应该包括 REPO A。我无法从本地存储库 REPO B 推送回原始(裸)存储库 REPO A,因为似乎存在结构错误。在 REPO B 中调用 git log
时,我得到:
error: Could not read 3c4168d
fatal: Failed to traverse parents of commit 3d8c67a
背景
在 2016 年,我开始推送“REPO A”,它位于 RaspBerry Pi Linux 计算机上作为裸存储库。自 2018 年以来,我不再推送到 REPO A,因为我是该项目中唯一的开发人员,并且更喜欢只提交到我的本地克隆“REPO B”。现在,三年后,我想继续推到REPO A,但在尝试时遇到了问题。这是structure of the two REPOs:
+----- HEAD -> master of REPO B
|
|
v
+---------+
d784821 | | latest commit
+---------+ 20 Mar 2021
|
+---------+
bcc1186 | | commit
+---------+ 14 Dec 2020
|
...
|
+---------+
REPO A 86dea25 | | commit
+---------+ 8 Nov 2018
HEAD -> master |
origin/master -----+ +---------+
origin/HEAD | f5ea2e3 | | commit
| +---------+ 7 Apr 2018
| |
| +~~~~~~~~~+
| | ? | -> error: Could not read 3c4168d
| +~~~~~~~~~+ -> fatal: Failed to traverse
v | parents of commit 3d8c67a
+---------+ +~~~~~~~~~+
commit | | 3c4168d = | |
13 Mar 2018 +---------+ +~~~~~~~~~+
| |
... = ...
| |
+---------+ +~~~~~~~~~+
commit | | 7ad262b = | |
2 Aug 2016 +---------+ +~~~~~~~~~+
| |
+---------+ +~~~~~~~~~+
initial commit | | 09b9c4d = | |
2 Aug 2016 +---------+ +~~~~~~~~~+
REPO A REPO B
推理
两个REPO的下半部分应该是相同的,因为REPO B包含了REPO A的延续。3c4168d
的HASH值,属于REPO A的最新提交,是相同的HASH值,即在尝试 git log
REPO B 时出现错误。因此,在 REPO B 的最旧有效提交 f5ea2e3
之后的向下连接不知何故丢失了。
当尝试使用 SourceTree 打开 REPO B 时,它拒绝设置显示错误消息的项目:
error code 128: refs/remotes/GitPi/master does not point to a valid object!
error: Could not read 3c4168d...
fatal: revision walk setup Failed
但是提交到 REPO B 仍然使用命令行。
问题
我如何“修复” REPO B 以便我找回当前丢失的提交历史记录(它仍然有效地位于 REPO A 中?我如何才能恢复 log
和 push
从再从 REPO B 到 REPO A?
我明白了,有很多帖子涉及粘合两个存储库和修复提交历史,但经过几个小时的阅读,我无法弄清楚我的具体情况。
感谢您的任何提示。
解决方法
经过一整天的阅读和尝试,问题可以解决;-)。这是,它是如何执行的。希望对某人有帮助:
概念
- 通过在 REPO A 的尖端创建一个新的“恢复提交”来修复提交链中缺失的链接,然后
- 为 REPO B 的每个有效提交创建补丁,然后
- 将补丁应用到 REPO A。补丁不查看 blob,而只包含更改的代码片段。从而使“重放”提交变得容易。
修复 REPO A 和 B 之间丢失的链接
找到两个有效提交 f5ea2e3
(Repo B) 和 3c4168d
之间的链接
cd RepoB
git show <sha-of-broken-commit>
- commit
3d8c67a
已损坏且未找到其父项 - 但对象可能没问题
上面的命令给出了树对象(参见文件夹)的 sha 以查找更多的 blob 对象(文件)。这样,尝试从损坏的提交 3d8c67a
中恢复所需的尽可能多的信息,以便在 REPO A 之上创建一个有效的提交 3c4168d
,它可以顺利地适应由提交 {{1} 强加的更改} 来自回购 B。
f5ea2e3
- 相应的树对象确实存在并且有效
- 在
git cat-file -p <sha-of-tree-object>
中更改的文件的相应 blob 对象存在且有效
现在,使用 Python 和 f5ea2e3
包恢复属于损坏提交 3d8c67a
的文件
zlib
从 REPO B 创建补丁
从提交 import zlib
fname = r'<path-to-object-within-object-folder-below-git-management-folder>'
compressed = open(fname,'rb').read()
decompressed=zlib.decompress(compressed)
fh = open("./<filename>",'w')
fh.write(decompressed.decode('utf-8'))
fh.close()
到 repo 结束在 REPO B 中创建补丁。
f5ea2e3
在回购 A 中应用补丁
将所有补丁应用到 REPO A 的尖端(在新的“恢复提交”之上)
cd ../RepoB
git format-patch f5ea2e3 -o _patches/