Git 交互式变基:如何自动移动其他分支(引用)?

Tom*_*nen 7 git rebase

有时我想做一个变基,并确保其他引用更新到新结构,而无需手动重置或多次变基。

有没有一种方法可以一次性完成,以便 git rebase 可以将引用更新为在 rebase 之前选择并具有引用的新提交?

一个例子:

Rebase前的情况:

* abc3... commit3 (branch:a, HEAD) 
* abc2... commit2 
* abc1... commit1 (branch:b)
* abc0... base commmit (branch:master)
Run Code Online (Sandbox Code Playgroud)

然后执行 Rebase master -i: pick abc3, abc1, abc2

结果将如下所示:(branch:b 保留在自己的提交分支中)

* abc6... commit2 (branch:a, HEAD) 
* abc5... commit1   
* abc4... commit3
|
| * abc1... commit1 (branch:b)
|/
* abc0... base commmit (branch:master)
Run Code Online (Sandbox Code Playgroud)

我希望结果看起来像:(分支:b 更新为新提交)

* abc6... commit2 (branch:a, HEAD) 
* abc5... commit1 (branch:b)
* abc4... commit3
* abc0... base commmit (branch:master)
Run Code Online (Sandbox Code Playgroud)

Dev*_*ode 9

update-refs以下是 git 2.39 的新功能如何帮助我的 rebase 流程的一般情况。

这个功能实际上可以从 git 2.38 开始使用,但它*有一些错误* - 你应该更新到2.39.0

首先,您应该使用以下配置设置启用此功能:

git config --global rebase.updateRefs true
Run Code Online (Sandbox Code Playgroud)

在进行交互式变基时,您现在可以轻松地使用分支名称标记任何提交。该分支名称也不需要已经存在。这可以轻松地将大量提交分解为小的 PR。

鉴于您在文件git rebase -i <base sha from master>内运行:git-rebase-todo

pick 1688e8706 First
pick d8e19832e Second
pick b34be474e Third
Run Code Online (Sandbox Code Playgroud)

您可以使用新的分支名称“标记”每个提交,然后推送这些分支,如下所示:

pick 1688e8706 First
update-ref refs/heads/first

pick d8e19832e Second
update-ref refs/heads/second

pick b34be474e Third
update-ref refs/heads/third

Run Code Online (Sandbox Code Playgroud)

注意:您基本上可以忽略refs/heads/前缀,后面的所有内容都是实际的分支名称!

如果您已经有这些指向这些 sha 的分支,这就是 git 为您编辑文件的方式。您只需执行一次[1],即可将分支名称与提交绑定。然后,如果您设置git config rebase.updateRefs true, git-rebase 会自动将这些update-ref refs/heads/branch-name行放入您的 git-rebase-todo 文件中。

然后,在每次变基成功完成后,您将看到:

Successfully rebased and updated refs/heads/third
Updated the following refs with --update-refs:
        refs/heads/first
        refs/heads/second
        refs/heads/third
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样推送每个分支:

git push --force-with-lease origin first:refs/heads/first
git push --force-with-lease origin second:refs/heads/second
git push --force-with-lease origin third:refs/heads/third
git push --force-with-lease origin $(git branch --show-current):refs/heads/$(git branch --show-current)
Run Code Online (Sandbox Code Playgroud)

为提交提供稳定的句柄本身并不激进,但这是一个手动步骤,在用户空间中执行起来非常容易出错。现在 git 已经实现了这一点,请注意更高级别的工具来为您提供全新的功能!

[1]:如果您git checkout second随后进行更改,git 将不会更新thirdthird在这种情况下,您通常应该更愿意保持在堆栈的顶部。如果您确实对 进行了更改second并最终想要 rebase third,您应该运行:

git checkout third
git rebase --onto second d8e19832e
Run Code Online (Sandbox Code Playgroud)

注意:d8e19832e在这种情况下实际上是正确的,根据我的例子,这是历史上的原始sha 。Git rebase 将获取其下面的所有内容,并将其丢弃,并尝试在 new 上应用提交“Third” ,并且您可能需要在此过程中解决冲突。secondthirdd8e19832esecond


Von*_*onC 1

git rebase 会将引用更新为在rebase之前选择并具有引用的新提交吗?

以前,没有。

但是当你重新设定基础时呢?或许。

在 Git 2.38(2022 年第 3 季度)中,“ git rebase -i( man )学习使用选项更新尖端出现在变基范围内的--update-refs分支。

请参阅Junio C Hamano ( )的提交 7fefa1b(2022 年 7 月 12 日)。 请参阅提交 4611884提交 aa37f3e、提交3113fed提交 b3b1a21提交 89fc0b5提交 900b50c提交 a97d791提交 d7ce9a2 、提交f57fd48提交 aa7f2fd提交 18ea595提交 1bec4d1 ( 1 2022 年 7 月 9 日)作者:Derrick Stolee ( )(由Junio C Hamano 合并 -- --提交 3d8e3dc中,2022 年 8 月 1 日)gitster
derrickstolee
gitster

rebase: 添加 --update-refs 选项

签署人:Derrick Stolee

在处理大型功能时,将该功能分解为多个较小的部分并按顺序进行审查会很有帮助。
在开发或审核期间,对功能的一部分进行更改可能会影响其中的多个部分。
交互式变基可以帮助调整分支的多部分“故事”。

但是,如果有分支跟踪功能的不同部分,则重新调整整个提交列表可能会创建从这些“子分支”无法访问的提交。
它可以采取手动步骤来更新这些分支。

向 ' ' ( man )添加一个新--update-refs选项,每当正在重新设置基数的提交用该步骤进行修饰时,都会将 'update-ref' 步骤添加到 todo 文件中。 最后,变基过程将所有列出的引用更新为变基操作期间存储的值。git rebase -i

确保在进行任何压缩或修复后进行迭代。
仅在这些压缩和修复完成后才更新分支。
这允许--fixup功能尖端的提交正确应用于子分支,即使它正在修复该部分中的最新提交。

此更改更新了文档和内置函数以接受该--update-refs选项,并使用“update-ref”命令更新待办事项文件。
添加测试以确保这些 todo 命令添加到正确的位置。

此更改不包括跟踪更新的引用并在变基过程结束时写入新的引用值的实际行为。
这将推迟到以后的更改。

git rebase现在包含在其手册页中:

--update-refs

--no-update-refs

自动强制更新任何指向正在重新确定基础的提交的分支。
在工作树中签出的任何分支都不会以这种方式更新。

和:

rebase:从“update-ref”命令更新参考

签署人:Derrick Stolee

之前的更改引入了 ' git rebase --update-refs' ( man )选项,该选项将 ' update-ref <ref>' 命令添加到todo交互式变基列表中。

教 Git 在到达这些“update-ref”命令时记录 HEAD 位置。
ref/before/after 三元组存储在$GIT_DIR/rebase-merge/update-refs文件中。
先前的更改解析了此文件,以避免在变基正在进行时让其他进程更新该文件中的引用。

我们不仅在定序器到达这些“update-ref”命令时更新文件,然后在变基序列末尾更新引用本身。
如果变基在最后一步之前中止,则引用不会更新。
“before”值用于确保我们不会意外删除同时更新的引用(例如,通过旧版本的 Git 或第三方工具)。

结果:

sequencer:通知用户--update-refs活动

报告人:Elijah Newren
签署人:Derrick Stolee

当用户运行' git rebase -i --update-refs' ( man )时,结束消息仍然显示only

Successfully rebased and updated <HEAD-ref>.
Run Code Online (Sandbox Code Playgroud)

更新定序器以收集由于该--update-refs选项而成功(和不成功)的引用更新,因此最终消息现在显示

Successfully rebased and updated <HEAD-ref>.
Updated the following refs with --update-refs:
efs/heads/first
efs/heads/third
Failed to update the following refs with --update-refs:
efs/heads/second
Run Code Online (Sandbox Code Playgroud)

git rebase --update-refs( man )update-ref在删除排序器中的所有命令时删除引用,这一问题已通过 Git 2.39(2022 年第 4 季度)得到纠正。

请参阅维多利亚·戴伊 (Victoria Dye )的提交 44da9e0(2022 年 11 月 7 日)。(由Taylor Blau 合并 -- --提交 35dc2cf中,2022 年 11 月 18 日)vdye
ttaylorr

rebase --update-refs:避免意外的引用删除

报告人:herr.kaste
帮助人:Phillip Wood
帮助人:Derrick Stolee
签字人:Victoria Dye
签字人:Taylor Blau

b3b1a21中(“ sequencer:在用户编辑待办事项列表时重写 update-refs”,2022-07-19,Git v2.38.0-rc0 -批量 #8中列出的合并)中,添加了 ' ' 步骤来处理 ' 的删除' 行来自 ' '。 具体来说,如果引用没有相应的“”行,它会从“”中删除潜在的引用更新。todo_list_filter_update_refs()update-refrebase-todo
update refs stateupdate-ref

但是,由于如果“ ”列表为空, “ write_update_refs_state()”将不会更新状态,因此删除所有“ ”行将导致状态与初始化方式保持不变(所有引用“after” OID 均为空)。 然后,当应用引用更新时,所有引用将被更新为 null 并因此被删除。refs_to_oidsupdate-ref

refs_to_oids要解决此问题,请在“ ”为空时删除“update-refs”状态文件。
此外,添加涵盖“所有 update-ref 行已删除”情况的测试。