修复 git 存储库中的连接并与旧存储库合并以保留历史记录

repair connection in git repo and merge with old repo to preserve history

问题

我有两个属于同一个项目的代码库“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的延续。属于REPO A最新commit的3c4168d的HASH值是相同的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 中?我怎样才能恢复 logpush 再次从 REPO B 到 REPO A?

我看到了,有很多帖子涉及粘合两个 repos 和修复提交历史记录,但经过几个小时的阅读,我无法针对我的具体情况弄清楚。

感谢任何提示。

经过一整天的阅读和尝试,问题得以解决;-)。这是它是如何执行的。希望对某人有所帮助:

概念

  1. 通过在 REPO A 的顶端创建一个新的“恢复提交”来修复提交链中缺失的 link,然后
  2. 为 REPO B 的每个有效提交创建补丁,然后
  3. 将补丁应用到 REPO A。补丁不查看 blob,而只包含更改的代码片段。从而使“重播”提交变得容易。

修复 REPO A 和 B 之间丢失的 LINK

在两个有效提交 f5ea2e3 (Repo B) 和 3c4168d

之间找到 link
cd RepoB
git show <sha-of-broken-commit>
  • commit 3d8c67a 已损坏且未找到其父项
  • 但对象可能没问题

上面的命令给出了树对象(cf. 文件夹)的 sha 以查找更多的 blob 对象(文件)。这样,尝试从损坏的提交 3d8c67a 中恢复尽可能多的信息,以便在 REPO A 之上创建一个有效的提交 3c4168d,它可以平滑地适应提交 [=15= 施加的更改] 回购 B.

git cat-file -p <sha-of-tree-object>
  • 相应的树对象确实存在并且有效
  • f5ea2e3 内更改的文件的相应 blob 对象存在且有效

现在,使用 Python 和 zlib

恢复属于损坏的提交 3d8c67a 的文件
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 B 创建补丁

从提交 f5ea2e3 开始在 REPO B 中创建补丁,直到 repo 结束。

cd ../RepoB
git format-patch f5ea2e3 -o _patches/

在 REPO A 中应用补丁

将所有补丁应用到 REPO A 的尖端(在新的“恢复提交”之上)

cd ../RepoA
cat ../RepoB/_patches/*.patch | git am