从项目的旧版本中恢复git历史记录

时间:2020-03-02 08:46:15

标签: git git-rebase git-cherry-pick git-workflow

长话短说:

  1. 项目正在迁移到新的git存储库服务器
  2. 有人只复制项目文件,并将整个项目作为初始提交推送到新服务器
  3. 在新的首次提交后,工作会持续相当一段时间
  4. 我设法找到了旧项目的本地副本(在切换到新服务器之前),并希望将旧的git历史记录插入到项目的当前版本中(在当前历史记录开始之前)。旧的本地项目中还有一些多余的提交

分支本质上是这样的:

                 old_master
                /
A--B--C--D--E--F

                  origin/new_master
                 /
init--G--H--I--J

其中提交:new_master-> init = old_master-> D

因此最终结果将类似于:

                       origin/new_master
                      /
A--B--C--D--G--H--I--J

How to rebase commits from another repository with a different history?具有类似的困境历史智慧,可以通过选择樱桃来解决。在我的情况下,有大量带有复杂分支的提交可能很难挑选。是否有使用rebaserebase --onto的有效方法?

1 个答案:

答案 0 :(得分:3)

是否有使用rebaserebase --onto的有效方法?

通常情况下不存在分支合并的情况。 (如果新存储库中的历史记录严格地是线性的,那么您可以使用简单的git rebase --onto来完成此操作。它的效率不是完全有效,只是机器时间,因此谁在乎它的效率如何? ?)

一般的解决方案是通过git replace graft

让我们看看使用上面的图将git fetch原始存储库和新存储库都同时放入第三(否则完全为空)存储库时会发生什么。您最终得到:

A--B--C--D--E--F   <-- old/master

D'--G--H--I--J   <-- new/master

(请注意,第三个存储库尚没有自己的master)。我没有调用new/masterinit中的第一次提交,而是将其称为D',因为它大概具有与提交{{1}相同的 snapshot }中的D中,但具有不同的 hash

没有什么(地球上没有权力)可以改变这些现有提交中的任何。但是,如果我们将提交old/master复制到父级为G的新提交G'会怎样?然后我们得到这个:

D

目前,新的提交A--B--C--D--E--F <-- old/master \ G' D'--G--H--I--J <-- new/master 只是在存储库中闲逛,我们无法查找。让我们添加一个名称,通过它我们可以找到G'。现在,我们将其称为G'

graft

现在,当Git沿着A--B--C--D--E--F <-- old/master \ G' <-- graft D'--G--H--I--J <-- new/master -然后-J-然后-I-然后-H-然后向后走时,如果我们能以某种方式获得Git,该怎么办-G链(然后停止),以便在最后一刻从D'切换到其嫁接G?也就是说,我们将建立某种形式的虚线连接:

G'

并说服Git运行A--B--C--D--E--F <-- old/master \ G' <-- graft : D'--G--H--I--J <-- new/master ,如 show git log然后J然后I然后H然后G'然后{{ 1}}然后D然后C

现在它看起来 历史记录将以这种方式读取,即使实际上不是这样。 1

这正是B所做的。它制作了替换对象。在提交的情况下,替换可以采用 graft 的形式,例如A。 Git并没有使用魔术名称git replace,而是使用了更魔术的名称G',其中 hash 是实际提交graft的哈希ID。有时候,您不需要知道这一点,而有时候,您知道。

默认情况下,这种refs/replace/hash不克隆 替换。 2 因此,您的第三个存储库是克隆时有点奇怪。有时候,这正是您想要的,如果是,那就很好。有时不是,如果是这样,请考虑使用G或类似的 convert 移植物到第四存储库中,该移植物现在是永久性的,因为提交被复制到具有新的和不同的哈希ID的 new 提交中,其中 real (但被重写)的历史记录使用嫁接的历史记录,而不是原始历史记录。


1 哲学问题:或者是吗?历史记录是按照历史记录的方式读取的,还是历史记录是Git向您读出的方式?

2 实际上,这是Git在脚注1中对哲学问题的回答。历史读取了Git向您读取的方式,但被记录记录为<真实的历史。克隆时,Git会克隆 real 历史记录,并忽略移植。克隆之后,您可以要求Git也复制嫁接 ,但这不是默认设置。

除此之外,您还可以运行git clone并查看真实的历史记录,并且在查看嫁接的历史记录时,每个嫁接都会标记一个可选的装饰,以便您仔细观察就可以看到它。