首页 > 解决方案 > 父分支合并到上游后从子分支提交拉取请求

问题描述

我有一个本地 git repo,它在 Github 中有一个远程上游。我在本地 repo 中为我正在开发的新功能创建了一个 branchA,然后为该分支提交了一个拉取请求。在等待这个 PR 合并到上游时,我想处理一些基于 branchA 的更多功能。所以我从 branchA 创建了一个新的 branchA1 并在该分支中进行了一些更改。

现在我的 branchA 的 PR 被压缩并合并到 Github 的远程上游,我想为我的 branchA1 提交 PR。我所做的是我首先从远程上游获取更改到我的本地主分支。然后我尝试git rebase master在 branchA1 中执行此操作,但此命令似乎正在删除我在 branchA1 中所做的所有更改。

如果我想从 branchA1 提交 PR,现在最好做什么?

如果我在工作流程中做错了什么,在等待来自父分支的 PR 被合并时处理新功能的正确方法是什么?

标签: gitgithub

解决方案


TL;DR:您可能想要git rebase --onto(这需要一些额外的参数)。

当你——或其他人;我将在这里使用“他们”并假设有人对您的原始拉取请求进行了“压缩和合并”,他们他们认为比您原始提交更好的单个新提交替换了您的提交。

但是,您仍然拥有原始提交。现在你的工作是git rebase复制你的 上的良好提交,而不是复制之前和现在只在 上的任何替换为更好的提交。A1A1AA1

以图片形式表示例如:

...--o--o--A   <-- master, origin/master
            \
             B--C--D   <-- branch-A
                    \
                     E--F--G   <-- branch-A1

其中每个大写字母代表一个提交,即,是在您开始时位于您(和他们)尖端的A提交的哈希 ID,您在您的 .masterBbranch-A

然后他们说:好的,我们喜欢你的B-C-D提交。但是我们将通过进行一个新的提交来“改进”它们,这H B++ all 组合成一个大提交的结果,我们将把它放在(your C)的Dmasterorigin/master末尾。与此同时,他们可能会或可能不会向他们master的提交更多提交——让我们抽出一轮o来代表任何此类无趣的提交。一旦你运行git fetch origin,你就会将他们的 提交(你已经有他们的旧提交)放到你的存储库中,更新你的origin/master

             o--H   <-- origin/master
            /
...--o--o--A   <-- master
            \
             B--C--D   <-- branch-A
                    \
                     E--F--G   <-- branch-A1

如果您git checkout mastergit merge origin/master,您将自己master前进以匹配您的origin/master

...--o--o--A--o--H   <-- master, origin/master
            \
             B--C--D   <-- branch-A
                    \
                     E--F--G   <-- branch-A1

branch-A仍然存在,除非你特别删除它。但即使你删除了它,你仍然有你的B-C-D提交:

...--o--o--A--o--H   <-- master, origin/master
            \
             B--C--D--E--F--G   <-- branch-A1

如果你现在git checkout branch-A1-git rebase master无论你的名字是否仍然branch-A指向你的提交D,他们为了支持他们而放弃了 - 你的HGit 现在将尝试复制所有六个提交,B-C-D-E-F-G, atop H,以尝试生成以下内容:

                   B'-C'-D'-E'-F'-G'   <-- branch-A1 (rebased)
                  /
...--o--o--A--o--H   <-- master, origin/master
            \
             B--C--D--E--F--G   [abandoned]

B但是在上面复制H不会顺利:它会与自身发生冲突,加上它需要的效果CD 删除。因此,这看起来就像您正在尝试删除自己的代码,只是在您复制C到. 无论如何,所有这些都是无用的。C'DD'

在这一点上,你想告诉 Git 的不是:复制我所有branch-A1未打开的提交master,以H在 的尖端进行master,而是:仅复制我的一些branch-A1未打开的提交上master,去追H在尖端master。在此特定示例中,您要复制的提交集是E-F-G. 你想最终得到:

                   E'-F'-G'   <-- branch-A1 (rebased)
                  /
...--o--o--A--o--H   <-- master, origin/master
            \
             B--C--D--E--F--G   [abandoned]

告诉 Git的方法git rebase --onto是使用,它接受两个参数而不是一个。您想要重新设置 *onto master,并且想要排除提交D和任何更早的内容(CBA以及 左侧的所有无聊提交A)。因此,如果您仍然具有branch-A标识 commit的名称D,则可以使用:

git checkout branch-A1             # make sure you're on the right branch
git rebase --onto master branch-A  # tell Git: copy only commits after branch-A

如果您没有name branch-A,您可以使用原始提交哈希 ID 作为限制器而不是 name branch-A,或者您可以运行git rebase -i master删除不需要的pick命令;或者你可以运行git log --all --decorate --oneline --graph和计算提交,或者你需要的任何东西,来找到提交。

请注意,在变基之后,您有一个 branch-A1的(历史与您之前的完全无关branch-A1,即使复制了三个提交以具有相同的效果)。因此,您需要将其强制推送到您用来处理拉取请求的任何 Web 服务(显然是 GitHub)。--force-with-lease如果您担心其他人可能会branch-A1在 GitHub 服务器上向您添加提交,则可以使用。


推荐阅读