在 GitHub "Squash and merge" 之后将分支变基到 master
Rebase branch after GitHub "Squash and merge" onto master
假设我在 branch1
上开发了一项功能,并使用 GitHub 合并请求将其发送出去进行代码审查。在审查期间,我会在 branch2
.
上做一些后续工作
branch2 -> D --> E --> F
/
branch1 -> A --> B --> C
/
master M
我的审稿人喜欢我的作品!无需更改。我使用 GitHub 的 Squash and merge 功能合并 branch1
的拉取请求。
在 master
上 运行 宁 git pull
并删除 branch1
后,我留下了这种情况:
branch2 -> A --> B --> C -> D --> E --> F
/
master M --> S
要为 branch2
发送一个看起来很干净的 PR,我想让我的提交树看起来像这样:
branch2 -> D' --> E' --> F'
/
master M --> S
S
处的代码("Squash and merge" 为 branch1
生成的提交)与 C
相同,因为它只是 [=26= 的压缩版本].
实现此目的的一种方法是 运行 在 branch2
:
上这样的序列
git reset --hard S
git cherry-pick D E F
但是以这种方式列出所有提交变得乏味,这真的感觉 像一个变基。 git rebase master
当然不会起作用,因为提交 A
、B
和 C
需要消失。
将分支从其祖先提交之一的压缩版本中变基的最佳方法是什么?
将 git rebase
与 --onto
结合使用。这仍然有点棘手,所以为了简单起见,您需要更早地做一件不同的事情。
我认为最好在 右侧 一侧绘制这些带有分支名称的图表,指向一个特定的提交。这是因为在 Git 中,提交在 多个分支 上,而分支名称实际上 do 仅指向一个特定的提交。也值得反转内部箭头(因为 Git 确实以这种方式存储它们)或仅使用连接线以免暗示错误的方向。
因此:
D--E--F <-- branch2
/
A--B--C <-- branch1
/
M <-- master
提交 A
到 C
确实在 branch1
和 branch2
上,而提交 D
F
到 branch2
只有 。 (提交 M
及更早版本在所有三个分支上。)
git rebase <em>upstream</em>
所做的是 select all1 提交 可从 当前分支到达,但 无法从 到达 upstream
参数,然后复制它们(使用 git cherry-pick
或等效项),以便它们在 upstream
提交之后立即出现。
在 squash-"merge"(不是真正的合并)之后,如果你 运行 git fetch
然后 fast-forward 你的 master
,你有和你画的一样,但我把 branch1
留在里面,把标签放在左边,然后在这里添加 origin/master
:
D--E--F <-- branch2
/
A--B--C <-- branch1
/
M--S <-- master, origin/master
(或者,如果您还没有 fast-forward 您的 master
,则只有 origin/master
指向提交 S
)。
你现在想要告诉 Git 用 cherry-pick 复制 D-E-F
,然后移动标签 branch2
指向最后复制的提交。您不想复制A-B-C
,因为它们已并入S
。您希望副本位于 S
之后,origin/master
现在指向它——无论您是否已更新 master
。因此:
git checkout branch2
git rebase --onto origin/master branch1
upstream
现在是 branch1
而不是 master
,但是 --onto
告诉 Git 在哪里放置副本:branch1
仅用于划定 不可复制的内容 。所以现在 Git 复制 D-E-F
并更改 branch2
指向那里:
D--E--F [abandoned]
/
A--B--C <-- branch1
/
M--S <-- master?, origin/master
\
D'-E'-F' <-- branch2
和现在你可以删除名字branch1
。 (现在你可以 fast-forward master
如果你还没有——你什么时候做并不重要,事实上你根本不需要你自己的 master
。 )
1更准确地说,rebase selects 提交是 (a) 不合并提交和 (b) 与 git patch-id
不同一些在排除集中提交,使用对称差异。也就是说,而不是 <em>upstream</em>..HEAD
,Git 实际上 运行s git rev-list
on <em>upstream</em>...HEAD
,用 --cherry-mark
或类似的,来挑选提交。根据特定类型的变基,实现略有不同。
假设我在 branch1
上开发了一项功能,并使用 GitHub 合并请求将其发送出去进行代码审查。在审查期间,我会在 branch2
.
branch2 -> D --> E --> F
/
branch1 -> A --> B --> C
/
master M
我的审稿人喜欢我的作品!无需更改。我使用 GitHub 的 Squash and merge 功能合并 branch1
的拉取请求。
在 master
上 运行 宁 git pull
并删除 branch1
后,我留下了这种情况:
branch2 -> A --> B --> C -> D --> E --> F
/
master M --> S
要为 branch2
发送一个看起来很干净的 PR,我想让我的提交树看起来像这样:
branch2 -> D' --> E' --> F'
/
master M --> S
S
处的代码("Squash and merge" 为 branch1
生成的提交)与 C
相同,因为它只是 [=26= 的压缩版本].
实现此目的的一种方法是 运行 在 branch2
:
git reset --hard S
git cherry-pick D E F
但是以这种方式列出所有提交变得乏味,这真的感觉 像一个变基。 git rebase master
当然不会起作用,因为提交 A
、B
和 C
需要消失。
将分支从其祖先提交之一的压缩版本中变基的最佳方法是什么?
将 git rebase
与 --onto
结合使用。这仍然有点棘手,所以为了简单起见,您需要更早地做一件不同的事情。
我认为最好在 右侧 一侧绘制这些带有分支名称的图表,指向一个特定的提交。这是因为在 Git 中,提交在 多个分支 上,而分支名称实际上 do 仅指向一个特定的提交。也值得反转内部箭头(因为 Git 确实以这种方式存储它们)或仅使用连接线以免暗示错误的方向。
因此:
D--E--F <-- branch2
/
A--B--C <-- branch1
/
M <-- master
提交 A
到 C
确实在 branch1
和 branch2
上,而提交 D
F
到 branch2
只有 。 (提交 M
及更早版本在所有三个分支上。)
git rebase <em>upstream</em>
所做的是 select all1 提交 可从 当前分支到达,但 无法从 到达 upstream
参数,然后复制它们(使用 git cherry-pick
或等效项),以便它们在 upstream
提交之后立即出现。
在 squash-"merge"(不是真正的合并)之后,如果你 运行 git fetch
然后 fast-forward 你的 master
,你有和你画的一样,但我把 branch1
留在里面,把标签放在左边,然后在这里添加 origin/master
:
D--E--F <-- branch2
/
A--B--C <-- branch1
/
M--S <-- master, origin/master
(或者,如果您还没有 fast-forward 您的 master
,则只有 origin/master
指向提交 S
)。
你现在想要告诉 Git 用 cherry-pick 复制 D-E-F
,然后移动标签 branch2
指向最后复制的提交。您不想复制A-B-C
,因为它们已并入S
。您希望副本位于 S
之后,origin/master
现在指向它——无论您是否已更新 master
。因此:
git checkout branch2
git rebase --onto origin/master branch1
upstream
现在是 branch1
而不是 master
,但是 --onto
告诉 Git 在哪里放置副本:branch1
仅用于划定 不可复制的内容 。所以现在 Git 复制 D-E-F
并更改 branch2
指向那里:
D--E--F [abandoned]
/
A--B--C <-- branch1
/
M--S <-- master?, origin/master
\
D'-E'-F' <-- branch2
和现在你可以删除名字branch1
。 (现在你可以 fast-forward master
如果你还没有——你什么时候做并不重要,事实上你根本不需要你自己的 master
。 )
1更准确地说,rebase selects 提交是 (a) 不合并提交和 (b) 与 git patch-id
不同一些在排除集中提交,使用对称差异。也就是说,而不是 <em>upstream</em>..HEAD
,Git 实际上 运行s git rev-list
on <em>upstream</em>...HEAD
,用 --cherry-mark
或类似的,来挑选提交。根据特定类型的变基,实现略有不同。