我经常使用git rebase -i
在发布之前清理我的历史记录。通常我想把提交编辑回当前分支分叉的地方,而不改变它的分叉点。我是这样做的:git rebase -i $(git show-branch --merge-base $PARENT_BRANCH HEAD)
这是一个丑陋的命令,我正在寻找一个更好的方法。只要我在做,我希望git能自动找出正确的父对象。
我 * 认为 * 我需要的是git rebase -i --fork-point $(something)
的别名,其中something
查找当前分支最近的共同祖先分支。它不需要是防弹的。如果它适用于线性主题分支,这就足够了。
3条答案
按热度按时间yeotifhr1#
有了Git 2.24(2019年第四季度),不再需要
git rebase -i --onto @{upstream}...HEAD
新的“
git rebase --keep-base <upstream>
“试图找到被重定基的主题的原始基,并在同一个基之上重定基,这在运行“git rebase -i
“(及其受限变体“git rebase -x
“)时很有用。该命令还学会了在更多情况下快进,而不是重放以重新创建相同的提交。
参见commit 414d924、commit 4effc5b、commit c0efb4c、commit 2b318aa(2019年8月27日)和commit 793ac7e、commit 359eceb(2019年8月25日),作者为Denton Liu (
Denton-L
)。帮助者:Eric Sunshine (
sunshineco
)、Junio C Hamano (gitster
)、Ævar Arnfjörð Bjarmason (avar
)和Johannes Schindelin (dscho
)。参见Ævar Arnfjörð Bjarmason (
avar
)的commit 6330209、commit c9efc21(2019年8月27日)和commit 4336d36(2019年8月25日)。帮助者:Eric Sunshine (
sunshineco
)、Junio C Hamano (gitster
)、Ævar Arnfjörð Bjarmason (avar
)和Johannes Schindelin (dscho
)。(由Junio C Hamano --
gitster
--合并至commit 640f9cd,2019年9月30日)重定基底:示教重定基底
--keep-base
一种常见的情况是,如果用户正在处理一个主题分支,并且希望对中间提交或自动压缩进行一些更改,他们将运行如下命令
以便保留合并基数。
这在向Git邮件列表贡献补丁序列时很有用,通常从当前的'
master
'开始。在开发补丁的同时,“
master
”也会被进一步开发,有时保持在“master”之上重定基并不是最好的主意,而是保持基提交不变。除此之外,如果用户希望在不改变任何内容的情况下测试主题分支中的各个提交,则可以运行
由于在分支和上游的合并基础上重定基是一种常见的情况,因此引入
--keep-base
选项作为一种快捷方式。这样我们就可以将上面的内容重写为
以及:
分别为。
git rebase
缐上手册现在包括:--keep-base
:将创建新提交的起点设置为合并基础
<upstream> <branch>
。运行“
git rebase --keep-base <upstream> <branch>
”等效于运行“git rebase --onto <upstream>... <upstream>
”。如果要在上游分支上开发特征,此选项非常有用。
在处理功能时,上游分支可能会前进,因此保持在上游分支之上重定基并不是最好的办法,而是保持基提交不变。
虽然这个选项和
--fork-point
都会在<upstream> and <branch>
之间寻找合并基底,但是这个选项会使用合并基底作为建立新提交的 * 起点 *,而--fork-point
则会使用合并基底来决定要重新设定基底的 * 提交集合 *。mvds建议在评论中将此与
git rebase --reapply-cherry-picks
结合在我的工作流程中,要为用C编写的固件开发一个最小的二进制补丁,我需要返回到某个提交哈希,进行分支,执行修改,并在生成的二进制文件中找到差异。
在那次提交之后的时间里,我们的编译器得到了升级,变得更加智能,将代码库变成了非编译代码。
为了解决这个问题,我挑选了所有需要再次编译的提交。
除非使用
--reapply-cherry-picks
,否则这些精心挑选的提交将打乱--keep-base
所完成的魔法。辩论在Git邮件列表中
在Git 2.39(Q4 2022)之前,“
git rebase --keep-base
”(man)用于丢弃已经被挑选到上游的提交,即使“keep-base”意味着在其上重建历史的库还不包括这些被挑选的提交。--keep-base
选项现在隐含--reapply-cherry-picks
和--no-fork-point
选项。请参阅commit aa1df81、commit ce5238a、commit d42c9ff、commit a770602、commit f21becd、commit b8dbfd0、commit 05ec418、commit 96601a2(2022年10月17日),作者为Phillip Wood (
phillipwood
)。(2022年10月30日由Taylor Blau --
ttaylorr
--合并至commit 003f815)第1331章:隐含
--no-fork-point
签署人:菲利普伍德
给定选项的名称,如果
--keep-base
实际上更改了分支的基址,而没有在命令行上显式给定--fork-point
,则会引起混淆。--keep-base
与显式--fork-point
的组合仍然受支持,即使--fork-point
意味着如果上游分支已经倒带,我们不保持相同的基数。我们这样做是为了防止任何人依赖[tested in
t3431
](https://lore.kernel.org/git/20200715032014.GA10818@generichostname/)的此行为git rebase
现在在其手册页中包括:git rebase --reapply-cherry-picks --no-fork-point --onto <upstream>...<branch> <upstream> <branch>
.git rebase
现在在其手册页中包括:如果在命令行中指定了
<upstream>
或--keep-base
,则默认值为--no-fork-point
,否则默认值为--fork-point
。另请参阅git config
中的rebase.forkpoint
。在Git 2.39中:
第1331章:隐含
--reapply-cherry-picks
报告人:菲利普·布兰
签署人:菲利普伍德
由于
--keep-base
不会重定分支的基,因此如果它删除了那些被挑选到上游分支的提交,就会造成混乱。由于
--reapply-cherry-picks
不受“apply”后端支持,因此此提交通过强制上游提交匹配onto提交(除非给出--no-reapply-cherry-picks
)来确保重新应用挑选。git rebase
现在在其手册页中包括:在上游之上重新建立基础,但保持基础提交不变。由于基础提交不变,此选项隐含
--reapply-cherry-picks
以避免丢失提交。git rebase
现在在其手册页中包括:如果没有
--keep-base
(或者如果给定了--no-reapply-cherry-picks
),这些提交将被自动丢弃。因为这需要阅读所有的上游提交,所以在有大量上游提交需要读取的仓库中,这可能是非常昂贵的。
当使用'merge'后端时,每个丢弃的提交都会发出警告(除非指定
--quiet
)。除非advice.skippedCherryPicks
设置为false,否则也会发出建议(请参阅git config
)。dgiusagp2#
首先,
--fork-point
用于远程跟踪名字,它的工作方式是使用上游提供的reflog,更多信息请参见Git rebase - commit select in fork-point mode。第二,但可能更重要的是,您可以运行
git rebase *upstream*
、git rebase --onto *newbase**upstream*
,甚至只运行git rebase
。当使用双参数形式时,您获得了很大的自由:upstream
* 参数限制了哪些提交将被复制。我们稍后会对此进行更多的讨论。newbase
* 参数选择哪一个提交是添加副本的点。这里的实际哈希ID非常重要。也就是说,当你 do 使用
--onto
时,你必须为--onto
*newbase
* 参数选择一个精确的提交。这意味着你可以非常宽松地使用什么作为 *upstream
* 参数。但是当你 * 不 * 使用--onto
时,*upstream
* 被用于 * 两种目的 。因此,upstream
* 参数是一个需要非常小心和精确的参数。一个目的是宽松和自由,另一个目的不是。这意味着你可以使用 * 两个 * 参数来重新获得你想要的(但可能不需要)额外的宽松,或者 * 没有 * 参数来获得方便。
(The由于问题的更新,下一部分的结构很奇怪。)
git show-branch --merge-base X Y
=git merge-base X Y
git show-branch
命令现在在给定多个参数时使用--merge-base
或--independent
。版本号为X
和Y
。(git merge-base
现在也接受--independent
,而不是仅仅采用octopus策略,但这只适用于使用三个或更多提交说明符的情况。)我更喜欢这里的
git merge-base
,因为我认为它更明显(当然输入起来也更短)。如果没有参数,则 upstream 来自分支设置
每个分支可以有一个(但只能有一个)上游设置。
任何分支 B 的上游设置通常是
origin/*B*
,因为我们倾向于将它们推送到GitHub或Bitbucket或某个企业Web服务器,我们将其URL保存在名称origin
下,这样我们就不必一直输入它。并且希望有一个git rebase
将自动使用的 second 设置,那么您就有点不走运了但是如果你 * 还没有 * 用完上游的那个,就把上游设置成你想让git rebase
自动使用的值。如果您现在在feature-X
上,并希望它基于develop
重新定基:现在
feature
将develop
作为它的一个上游。运行git rebase
(带或不带-i
)将重定基,就像运行带有develop
作为其 *upstream
* 参数的相同命令一样。如果您已经用完了上游的别名,则可以创建自己的别名:
(pick一些名字):这允许你使用
git config
,为develop
配置一个额外的名称,branch.feature-X.base
。$(git symbolic-ref --short)
提取当前分支名称,git config --get
获取设置,然后rebase使用它作为它的一个上游参数。单一限制器和目标/ newbase参数的缺点
这里的缺点是,给定以下形式的图:
最后得到的是
develop
提示之后的副本:当你想把副本保存在同一个地方时,只需修改提交文本或者把两个副本挤在一起:
使用
--onto
对于双参数形式,
--onto
参数选择目标提交:现在副本将在
*
之后进行。要复制的提交集实际上是通过使用*upstream*..feature-X
来确定的:也就是说,通过从feature-X
开始并向后工作可到达的提交,但是不包括通过从 *upstream
* 开始并向后工作可到达的提交。现在你只需要找到提交
*
。如果你有两个名字,比如feature-X
和develop
,你可以使用gitrevisions three-dot syntax,develop...feature-X
或feature-X...develop
(当只有一个合并基时,语法是对称的)来指定提交*
。这只在新版本的Git中有效:在旧版本中,使用git show-branch
或git merge-base
(使用两个提交哈希ID,它们的行为方式相同)。指定提交
*
作为--onto
目标后,你可以再次允许分支的上游作为限制器。也就是说,你可以省略显式的 *upstream
*,因为它默认为实际的上游。而且,由于你可以使用@{upstream}
或@{u}
语法,你可以创建一个非常短和简单的别名,就像你在自己的答案中所做的那样。如果你想保留一个独立的上游(
origin/feature-X
)和基,你可以回到为每个分支名称配置一个额外值的想法。在这种情况下,你需要使用它两次,所以你可能需要一个完整的脚本来代替别名,在那里你可以进行错误检查:将其命名为
git-base
,并将其放在路径中,现在就可以运行git base
了。a8jjtwal3#
经过一个小时左右,我找到了一个足够好的东西。如果分支有一个上游集合,并且如果上游集合是我想要比较的集合,这个命令就可以完成我想要的任务:
这些三点并不像git-log和类似的命令那样执行相同的操作。
作为一种特殊情况,如果正好有一个合并基,则可以使用“A... B”作为A和B的合并基的快捷方式。
所以这就是说“找到HEAD的合并基和它自己的上游,然后根据它来重定基”。通常本地分支没有上游,但是可以设置它,并且有一个gitconfig选项(autoSetupMerge)会自动为新分支做这个操作。因此:
在此之后,我可以编辑历史回到分支点很容易:
而且它对所有未来的分支机构都有效。
(note:请参阅torek's answer,以了解此处的详细说明)