我有一个本地 git 存储库,它在 Github 中有一个远程上游。我在本地存储库中为我正在处理的新功能创建了一个分支 A,然后为该分支提交了拉取请求。在等待此 PR 合并到上游时,我想开发更多基于 branchA 的功能。所以我从分支 A 创建了一个新的分支 A1,并在该分支中进行了一些更改。
现在我的分支 A 的 PR 是挤压并合并到 Github 中的远程上游,我想为我的分支 A1 提交一个 PR。我所做的是首先将更改从远程上游获取到我的本地主分支。然后我尝试在 branchA1 中执行git rebase master
,但此命令似乎删除了我在 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
是你(和他们)开始时master
顶端的提交的哈希ID,B
是你在branch-A
上所做的第一次提交,依此类推。
然后他们说:好的,我们喜欢你的B-C-D
提交。但是我们将通过进行新的提交来"改进"它们H
这是将B
+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
指向他们为了他们的H
而扔掉的提交D
——你的 Git 现在将尝试复制所有六个提交,B-C-D-E-F-G
,在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]
但是在H
上复制B
并不顺利:它会与自身发生冲突,而且它需要C
的效果,D
消除。 因此,这看起来像您正在尝试删除自己的代码,只是在将C
复制到C'
然后D
复制到D'
时将其再次放回。 无论如何,所有这些都是无用的。
master
上branch-A1
上的所有提交,以便在master
的尖端进行H
,而是:只复制我在branch-A1
上的一些不在master
上的提交,以便在master
的尖端进行H
。在此特定示例中,要复制的提交集是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
,它需要两个参数而不是一个参数。 你想在master
上重定*的基数,并且你想排除提交D
和任何更早的东西(C
,B
,A
,以及A
左侧的所有无聊提交)。 因此,如果您仍然具有标识提交D
branch-A
的名称,则可以使用:
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
如果您没有名称branch-A
,则可以使用原始提交哈希 ID 作为限制器而不是名称branch-A
,或者可以运行git rebase -i master
并删除不需要的pick
命令;或者您可以运行git log --all --decorate --oneline --graph
并计数提交或任何您需要的内容来查找提交。
请注意,变基后,您有一个新的branch-A1
(与之前的branch-A1
完全无关,即使复制了三个提交以具有相同的效果)。 因此,您需要将其强制推送到您用于处理拉取请求的任何 Web 服务(显然是 GitHub)。 如果您担心其他人可能会在 GitHub 服务器上向您branch-A1
添加提交,则可以使用--force-with-lease
。