【问题标题】:Git repository has two starting commits - how can I merge them?Git 存储库有两个起始提交 - 我如何合并它们?
【发布时间】:2017-05-23 12:31:38
【问题描述】:

我正在将存储库从 TFS 转换为 Git,由于某种原因,我的历史开始看起来像这样:

*   - Merge from Staging
|\
| * - Foo
| * - Branched from $/TFS/Main
* - Branched from $/TFS/Staging

即我有两个相互合并的不相关的初始提交。两个初始提交或多或少是等价的,所以我想做的是“挤压”Merge from StagingBranched from $/TFS/Staging 提交,有效地删除 Branched from $/TFS/Staging 提交,这样我的历史看起来像这样:

* - Merge from Staging
* - Foo
* - Branched from $/TFS/Main

据我所知,正常的执行方式是在分支分歧之前从提交开始的交互式变基,但我在这个存储库中没有这样的提交。

我该如何解决这个烂摊子?

【问题讨论】:

    标签: git git-rewrite-history


    【解决方案1】:

    我从来没有使用过 TFS(更不用说 TFS 到 Git 的转换程序),也不能说为什么你得到了你所做的,但这里的问题是你实际上有两个单独的根提交,这只能变成通过合并提交相关。 Git 需要每个提交通过来自每个提交节点(提交 DAG 中的顶点)的父链接(传出弧)可访问。此外,Git 的工作方式是从末尾开始(通过标签找到的最新提交)并向后工作。

    让我重新绘制图表,以便我可以用一个字母标记每个提交(并添加更多间距,以增强视觉效果)。

    D   - Merge from Staging
    |\
    | C - Foo
    | |
    | B - Branched from $/TFS/Main
    |
    A - Branched from $/TFS/Staging
    

    Commit Dtip 提交,大概上面有分支标签 master,这样 Git 就可以找到了。

    提交 AB 都是根。提交C 是一个非根提交,其父提交是B。提交D 将两个分支联系在一起:一个分支植根于B,另一个植根于(并且仅包含)A

    您的目标是完全放弃A。为此,您还必须丢弃D。这可能太激烈了。

    复制并丢弃D

    当您丢弃D 时,您放弃了存储在提交D 下的树快照与存储在提交C 下的树快照之间的任何差异。这可能也可能不是您想要的。 DC 之间可能没有区别,或者没有显着差异。 (要找出答案,请让 Git 直接比较提交 CD:例如 git diff <hash-ID-of-C> <hash-ID-of-D>。)

    如果您希望保留D,同时丢弃D 本身的提交,您需要将该树复制 到一个新的提交中。有很多方法可以做到这一点,但最简单的可能是挑选合并:直接检查提交C(通过哈希ID),在那里创建一个分支git cherry-pick -m <mainline-number> <hash-or-name-for-D>。您使用的“主线编号”(1 或 2)决定了 Git 带来的更改集:比较 DC 时的更改,或者比较 DA 时的更改。您希望在比较 DC 时获得那些,以便最终提交具有与 D 相同的 tree

    (由于某些转换器大概制作了D,我不知道它在进行此合并提交时如何安排父链接。所以我不知道您是要-m 1还是-m 2。一个解决这个问题的另一种方法是使用 Git 的 管道命令,在本例中为 git commit-tree,但这更难以描述:管道命令用于脚本,而不是供人类使用。 )

    因此,假设分支名称master 标识提交D

    $ git checkout <hash-id-of-C>
    $ git checkout -b new-master
    $ git cherry-pick -m <number> master
    

    结果是如下图:

    D   - Merge from Staging  (master)
    |
    | E - copy of D           (new-master)
    |\|
    | C - Foo
    | |
    | B - Branched from $/TFS/Main
    |
    A - Branched from $/TFS/Staging
    

    您现在可以继续下面的“丢弃 D”步骤。

    丢弃D

    如果提交D 无用,您可以完全删除D,根本不用费心将树复制到新提交。这更容易,因为您不必挑选樱桃(或git commit-tree)。

    或者,如果您已经成功地将D 复制到E,您现在可以丢弃D,因为E 有您想要的副本。

    要做那个——现在丢弃D——你只需要强制分支名称(我在这里再次假设master)直接指向提交C

    $ git checkout master
    $ git reset --hard <hash-id-of-C>
    

    这意味着 Git 将首先查看提交 C,这是您想要保留的第二个,然后继续查看 C parent,即 B。然后 Git 会尝试继续到 B 的父级,但由于它是根提交并且 没有 没有父级,Git 会停在那里,并且您只有提交 CB。原始的 DA 仍然存在,在您的存储库中,通过 Git 的 reflogs 保存了一段时间。最终,reflogs 也会过期,提交 AD 变得不受保护,Git 的 垃圾收集器 git gc 将它们永远删除。

    重新合并副本

    如果你在分支new-master 上提交了E,现在是时候拿起它了。你现在有了这个:

    D   - Merge from Staging  [abandoned - no name]
    |
    | E - copy of D           (new-master)
    |\|
    | C - Foo                 (master)
    | |
    | B - Branched from $/TFS/Main
    |
    A - Branched from $/TFS/Staging
    

    我们可以在没有DA 的情况下重新绘制:

    E - copy of D           (new-master)
    |
    C - Foo                 (master)
    |
    B - Branched from $/TFS/Main
    

    我们所要做的就是让 Git 将名称 master“向前”移动,使其指向提交 E

    $ git checkout master
    $ git merge --ff-only new-master
    

    例如。这给了我们:

    E - copy of D           (master, new-master)
    |
    C - Foo
    |
    B - Branched from $/TFS/Main
    

    请注意,commit 是如何变化的,永远。我们只需添加 new 提交。除了新的提交之外,真正的变化是分支名称(如master)会四处移动,以便它们指向更新的提交——或者,对于像我们的git reset 这样的特殊情况,它们甚至可能“向后”移动。

    【讨论】:

      【解决方案2】:

      如果你想修复历史,有几种方法:

      Merge from Staging 提交,您可以运行:

      # if $hash is the hash of the '- Foo' commmit :
      git rebase -i $hash
      
      # you will see a list with one commit :
      # set the command to "edit" (instead of "pick")
      # close the editor
      
      # when git says "You can amend the commit ...", run :
      git rebase --continue
      

      【讨论】:

      • 嗯,所以当我这样做时,我遇到了合并冲突,我不明白
      • 我在交互式 rebase 中尝试了很多选项,但到目前为止都没有成功 - squash 告诉我 error: cannot 'squash' without a previous commit,其他选项都没有摆脱那个额外的悬空提交跨度>
      • 这通常是处理这种事情的一种方法,但对于这种情况它根本不起作用。通常,rebase 会完全删除合并,但您必须有一个开始提交来进行 rebase。这里有两个潜在的起点,都是根提交; rebase 不准备处理这个问题。
      猜你喜欢
      • 2010-09-30
      • 2010-11-28
      相关资源
      最近更新 更多