使用git rebase命令将分支与其祖父合并

3
我正在阅读关于git rebase的内容,浏览了git-scm文档。我有一个具体的问题,关于使用onto功能将分支rebase到其祖先(就像上面链接中的情况)。假设我们有以下分支/提交结构:
C1 <- C2 <- C5 <- C6 [master]
         <- C3 <- C4 <- C10 [server]
               <- C8 <- C9 [client]

现在,我想将client分支合并到master分支。我切换到了client分支并运行了git rebase --onto master server client命令。运行该命令后,我得到的结果结构是(在将master合并和快进到client之后):
C1 <- C2 <- C5 <- C6 <- C8' <- C9' [master, client]
         <- C3 <- C4 <- C10 [server]

我的疑问是,如果我对client分支的更改取决于server分支中的C3提交,那么在这种情况下,在合并操作后master分支中的代码肯定会失败。据我所知,实际结果(在将主分支快进到客户端之后合并)不应该像这样:
 C1 <- C2 <- C5 <- C6 <- C3' <- C8' <- C9' [master, client]
                             <- C4 <- C10 [server]

请问我的理解/担忧是否有误?

1
  1. 你把第二个图标错标了。master 应该是 client
  2. 在第三个图标中(同样错标),为什么你期望 server 改变呢?毕竟你只是在重新定位 client
- jcm
@AndrewC 是的,我只是跳过/假设了那些步骤,以便问题简短。关于rebase无法进行,恐怕不是这种情况,rebase只是从“client”分支获取提交并继续。实际问题是,正如jthill的答案所指出的那样,我提到了“错误的上游”。 - face
跳过/假设步骤是得到混乱答案和问题被投票反对的好方法。只有在没有依赖关系的情况下,才应该继续进行变基。 - Andrew C
@AndrewC 已经注意到了,谢谢!但是我还是不明白如何停止rebase。假设提交C3添加了一个新对象“Cache”,该对象将被服务器和客户端使用。现在在提交C8和C9中,我正在使用此对象,因此C8对C3有依赖性,但是rebase仍将继续,将基础对象类“Cache”留在服务器分支中,并将C8和C9单独提交到客户端分支中。 - face
你是说你尝试过这个并且成功了吗?当我执行(client)$ git rebase --onto master HEAD~1时,我得到了无法合并更改。在0001处补丁失败和更多的错误输出,导致rebase停止。 - Andrew C
显示剩余2条评论
2个回答

2

If you start from

C1---C2---C5---C6  master
       \
        C3---C4---C10  server
          \
           C8---C9  client

你希望看到的结果是什么?
C1---C2---C5---C6---C3'---C8'---C9' master, client
                      \
                       C4---C10  server

这里存在一个误解:

C3'不能成为C4的祖先。这种情况不可能发生。

当您执行以下操作时:

git rebase --onto master server client

由于您所说的,客户端中的更改“取决于”来自C3的更改,因此您可以解决合并问题,并获得

C1---C2---C5---C6  master
       \         \
        \         C8'---C9' client
         \
          C3---C4---C10  server

现在,在你合并了master和client之后,准备rebase server时,有两种情况可能发生:

1. 如果你在之前的冲突中保留了依赖于C3的C8更改,在解决当前冲突后,git会说

没有更改-您是否忘记使用 'git add'?如果没有需要提交的内容,很可能是其他东西已经引入了相同的更改;您可能想要跳过此补丁

解决这个问题后,请运行 "git rebase --continue"。如果您想跳过此补丁,请运行 "git rebase --skip"。要检出原始分支并停止rebasing,请运行" git rebase --abort"。

然后你可以执行

git rebase --skip

你会得到:

C1---C2---C5---C6---C8'---C9'  master, client  
                             \         
                              C4'---C10' server

请注意,由于更改已应用到 C8' 上,因此没有 C3'

2. 如果您在之前的冲突中没有保留与 C3 相关的来自 C8 的更改,则在解决当前冲突并执行操作后,请执行以下操作:

git rebase --continue

你将会得到:

C1---C2---C5---C6---C8'---C9'  master, client
                             \         
                              C3'---C4'---C10' server

这意味着当在重新定位时,<branch><upstream> 的更改与 <newbase> 冲突时,Git 会提供合并解决机制来选择是立即还是稍后应用这些更改。请注意保留 HTML 标签。

假设我还没有准备好将服务器变基到我的主分支。我需要使用变基来实现线性历史记录,将客户端的代码与主分支合并。但这会失败,因为提交“C3”不存在,而我对“client”分支进行的提交(C8 和 C9)依赖于它。 - face
仅供澄清,在上面的评论中,合并操作会成功,但结果代码会失败。 - face
C3的提交对象不存在,但您可以解决冲突,以包括从C3所需的更改,使得生成的代码能够工作。如果您不准备集成来自C3的所有更改,只想要客户端分支所需的更改,则可以使用此功能。否则,您可以执行 git rebase master client - Ed I

1
我的疑问是,如果客户端分支中的更改依赖于服务器分支中的C3提交,那么主分支中的结果代码肯定会失败,因为rebase不会包含C3提交。是的。您已经明确地将提交C3从重新基于的历史记录中切出来了。为什么要这样做?只需git rebase master client。当您合并服务器时,git不会再次尝试应用C3更改,因为它们不会显示在差异中(或者对这些行进行进一步更改将导致冲突)。编辑:提交不是“在”分支上的。历史很重要。分支名称只是轻量级(在这里,“可丢弃”不是一个坏词)引用,以帮助识别您感兴趣的提交。专注于提交本身及其祖先。

谢谢,那起作用了!因此,历史记录的服务器端保持不变,并且当我在服务器上运行rebase(当然是在快进主分支之后)时,它会自动对齐并跳过已经提交到上游的更改。太棒了! - face

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接