git - 父分支合并到上游后从子分支提交拉取请求
问题描述
我有一个本地 git repo,它在 Github 中有一个远程上游。我在本地 repo 中为我正在开发的新功能创建了一个 branchA,然后为该分支提交了一个拉取请求。在等待这个 PR 合并到上游时,我想处理一些基于 branchA 的更多功能。所以我从 branchA 创建了一个新的 branchA1 并在该分支中进行了一些更改。
现在我的 branchA 的 PR 被压缩并合并到 Github 的远程上游,我想为我的 branchA1 提交 PR。我所做的是我首先从远程上游获取更改到我的本地主分支。然后我尝试git rebase master
在 branchA1 中执行此操作,但此命令似乎正在删除我在 branchA1 中所做的所有更改。
如果我想从 branchA1 提交 PR,现在最好做什么?
如果我在工作流程中做错了什么,在等待来自父分支的 PR 被合并时处理新功能的正确方法是什么?
解决方案
TL;DR:您可能想要git rebase --onto
(这需要一些额外的参数)。
当你——或其他人;我将在这里使用“他们”并假设有人对您的原始拉取请求进行了“压缩和合并”,他们用他们认为比您原始提交更好的单个新提交替换了您的提交。
但是,您仍然拥有原始提交。现在你的工作是只git rebase
复制你的 上的良好提交,而不是复制之前和现在只在 上的任何替换为更好的提交。A1
A1
A
A1
以图片形式表示,例如:
...--o--o--A <-- master, origin/master
\
B--C--D <-- branch-A
\
E--F--G <-- branch-A1
其中每个大写字母代表一个提交,即,是在您开始时位于您(和他们)尖端的A
提交的哈希 ID,是您在您的 .master
B
branch-A
然后他们说:好的,我们喜欢你的B-C-D
提交。但是我们将通过进行一个新的提交来“改进”它们,这H
是将 B
++ all 组合成一个大提交的结果,我们将把它放在(your C
)的D
master
origin/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 master
和git 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
,他们为了支持他们而放弃了 - 你的H
Git 现在将尝试复制所有六个提交,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
不会顺利:它会与自身发生冲突,加上它需要的效果C
和D
删除。因此,这看起来就像您正在尝试删除自己的代码,只是在您复制C
到. 无论如何,所有这些都是无用的。C'
D
D'
在这一点上,你想告诉 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
和任何更早的内容(C
、B
、A
以及 左侧的所有无聊提交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 服务器上向您添加提交,则可以使用。