Git 2.18(2018年第二季度)将通过添加新选项显著改进--preserve-merge
选项。
"git rebase
"学会了"--rebase-merges
",可以在其他地方移植整个提交图的拓扑结构。
(注意:Git 2.22(2019年第二季度)实际上弃用 --preserve-merge
,而Git 2.25(2020年第一季度)停止在"git rebase --help
"输出中宣传它)
请查看 commit 25cff9f, commit 7543f6f, commit 1131ec9, commit 7ccdf65, commit 537e7d6, commit a9be29c, commit 8f6aed7, commit 1644c73, commit d1e8b01, commit 4c68e7d, commit 9055e40, commit cb5206e, commit a01c2a5, commit 2f6b1d1, commit bf5c057 (2018年4月25日) 由 Johannes Schindelin (dscho
) 提交。
请查看 commit f431d73 (2018年4月25日) 由 Stefan Beller (stefanbeller
) 提交。
请查看 commit 2429335 (2018年4月25日) 由 Phillip Wood (phillipwood
) 提交。
(于2018年5月23日被Junio C Hamano -- gitster
--合并至commit 2c18e6a)
pull
: 接受 --rebase-merges
以重新创建分支拓扑结构
类似于将
--preserve-merges
选项传递给
rebase
命令的
preserve
模式,
merges
模式只是传递了
--rebase-merges
选项。
这将允许用户在拉取新提交时方便地重新创建非平凡提交的拓扑结构,而不会使它们变得扁平化。
git rebase
的 man 页面现在有一个专门介绍合并历史的变基部分。
摘录:
There are legitimate reasons why a developer may want to
recreate merge commits: to keep the branch structure (or "commit
topology") when working on multiple, inter-related branches.
In the following example, the developer works on a topic branch that
refactors the way buttons are defined, and on another topic branch
that uses that refactoring to implement a "Report a bug" button.
The output of git log --graph --format=%s -5
may look like this:
* Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one
The developer might want to rebase those commits to a newer master
while keeping the branch topology, for example when the first topic
branch is expected to be integrated into master
much earlier than the
second one, say, to resolve merge conflicts with changes to the
DownloadButton
class that made it into master
.
This rebase can be performed using the --rebase-merges
option.
请参见提交 1644c73,其中包含一个小例子:
rebase-helper
--make-script
:引入一个标志以重定基合并
The sequencer just learned new commands intended to recreate branch
structure (similar in spirit to --preserve-merges
, but with a
substantially less-broken design).
Let's allow the rebase--helper
to generate todo lists making use of
these commands, triggered by the new --rebase-merges
option.
For a commit topology like this (where the HEAD points to C):
- A - B - C (HEAD)
\ /
D
the generated todo list would look like this:
pick 0123 A
label branch-point
pick 1234 D
label D
reset branch-point
pick 2345 B
merge -C 3456 D
--preserve-merge
有什么区别吗?
Commit 8f6aed7 解释道:
从前,这里的开发人员想到:如果能够将 Git for Windows 在核心 Git 上的补丁表示为一堆分支,并在核心 Git 上重新创建一个樱桃挑选的系列以维护它,那么岂不是很好?
最初的尝试是:git rebase --preserve-merges
。
然而,那个实验从未被视为交互式选项,而是只在 git rebase --interactive
上搭便车,因为那个命令的实现看起来非常熟悉:那是同一个设计了 --preserve-merges
的人:作者本人。
在“亲笔”一词中,作者指的是他自己:Johannes Schindelin (dscho
),他是 Git For Windows 的主要原因(与其他几位英雄 - Hannes、Steffen、Sebastian等人一起 - 即使回到那个时代 - 2009年 - 那也不容易)。
自2015年9月以来,他一直在微软工作since Sept. 2015,这是有道理的,考虑到微软现在大量使用Git并需要他的服务。
实际上,这种趋势始于2013年,当时TFS。从那时起,微软管理地球上最大的Git存储库!而且,自2018年10月以来,微软收购了GitHub。
您可以在2018年4月的Git Merge 2018中观看 Johannes的讲解视频。
过了一段时间,另一个开发人员(我指的是你,Andreas!;-))决定允许--preserve-merges
与--interactive
相结合(有附带条件!),而Git维护者(实际上是在Junio离开期间的临时Git维护者)同意了。这也是--preserve-merges
设计的魅力开始迅速破裂并变得不再美好的时候。
这里的Jonathan谈论的是来自Suse的Andreas Schwab。
您可以看到他们在2012年的一些讨论。
原因是什么?在“--preserve-merges”模式下,合并提交的父提交(或任何提交)没有明确说明,而是通过传递给“pick”命令的提交名称隐含表示。这使得例如重新排序提交变得不可能。更不用说将提交移动到其他分支或将主题分支拆分为两个了。
遗憾的是,这些缺点也阻止了该模式(其最初的目的是为Git for Windows的需求服务,并带有额外的希望它也可能对其他人有用)来满足Git for Windows的需求。
五年后,Git for Windows中有一个笨重、大杂烩的部分相关、部分无关的补丁系列,这是基于核心Git的标签不时地进行变基(赢得了那个注定失败的git-remote-hg系列的开发者的不应得的愤怒,该系列首先淘汰了Git for Windows的竞争方法,但后来被放弃了),这真的是不可行的。于是 "
Git garden shears"
诞生了:这是一个脚本,附加在交互式变基之上,首先确定要变基的补丁的分支拓扑结构,创建一个伪待办事项列表以供进一步编辑,将结果转换为真正的待办事项列表(大量使用“exec”命令来“实现”缺失的待办事项命令),最后在新的基础提交之上重新创建补丁系列。
(在此补丁中引用了 Git 修剪剪刀脚本,commit 9055e40)
那是在2013年。
需要大约三周的时间来设计并实现一个独立的脚本。不用说,这个实现需要很多年才能稳定下来,而设计本身则证明了自己是可靠的。
通过这个补丁,Git修剪剪刀的好处可以应用到git rebase -i
中。
传递--rebase-merges
选项将生成一个易于理解的待办���项列表,并且很明显如何重新排序提交。
可以通过插入label
命令并调用merge <label>
来引入新分支。
一旦这种模式变得稳定并被广泛接受,我们就可以废弃设计错误的--preserve-merges
。
Git 2.19(2018年第三季度)通过使其与--exec
一起工作,改进了新的--rebase-merges
选项。
在"git rebase --rebase-merges
"中使用"--exec
"选项会将执行命令放置在错误的位置,这已得到纠正。
请查看 commit 1ace63b(2018年8月9日)和 commit f0880f7(2018年8月6日),作者是Johannes Schindelin (dscho
)。
(由Junio C Hamano -- gitster
--合并于commit 750eb11,2018年8月20日)
rebase --exec
:使其与--rebase-merges
一起工作
--exec
的想法是在每个 pick
后面附加一个 exec
调用。
自从引入了 fixup!
/squash!
提交后,这个想法被扩展到适用于“可能跟随 fixup/squash 链的 pick”,即在 pick
和其对应的任何 fixup
或 squash
行之间不会插入 exec。
当前的实现使用了一个小技巧来实现这一点:它假设只有 pick/fixup/squash 命令,然后在第一个以外的任何 pick 前插入 exec 行,并追加最后一个 exec 行。
使用 git rebase --rebase-merges
生成的待办事项列表时,这种简单的实现显示出了它的问题:当存在 label、reset 和 merge 命令时,它会产生完全错误的结果。
让我们改变实现方式,确切地做我们想要的事情:查找 pick 行,跳过任何 fixup/squash 链,然后插入 exec 行。反复洗涤。
注意:我们尽可能在注释行之前插入,因为空提交由注释的 pick 行表示(我们希望在这样的行之前插入前一个 pick 的 exec 行,而不是在其后面)。
顺便说一下,在 merge 命令之后也添加 exec 行,因为它们与 pick 命令类似:它们添加新的提交。
Git 2.22(2019 年第二季度)修复了使用 refs/rewritten/ 层次结构来存储 rebase 中间状态的问题,这从本质上使得该层次结构针对每个工作树。
请查看提交 b9317d5, 提交 90d31ff, 提交 09e6564 (2019年3月7日) 由Nguyễn Thái Ngọc Duy (pclouds
)完成。
(由Junio C Hamano -- gitster
--在提交 917f2cd中合并,2019年4月9日)
确保后缀 /refs/rewritten/ 是每个工作树独立的
a9be29c (连续器: 使由 label
命令生成的引用工作树本地化,2018-04-25,Git 2.19)将 refs/rewritten/
作为每个工作树引用空间添加。
不幸的是(我的错),有几个地方需要更新以确保它真正是每个工作树独立的。
```
жӣҙж–°дәҶ`add_per_worktree_entries_to_dir()`пјҢзЎ®дҝқеј•з”ЁеҲ—иЎЁжҹҘзңӢжҜҸдёӘе·ҘдҪңж ‘зҡ„`refs/rewritten/`иҖҢдёҚжҳҜжҜҸдёӘд»“еә“зҡ„гҖӮ
жӣҙж–°дәҶ`common_list[]`пјҢдҪҝеҫ—`git_path()`иҝ”еӣһжӯЈзЎ®зҡ„дҪҚзҪ®гҖӮ иҝҷеҢ…жӢ¬вҖңrev-parse --git-pathвҖқгҖӮ
иҝҷдёӘж··д№ұжҳҜжҲ‘еҲӣе»әзҡ„пјҢжҲ‘ејҖе§Ӣе°қиҜ•дҪҝз”Ё`refs/worktree`жқҘдҝ®еӨҚе®ғпјҢе…¶дёӯжүҖжңүеј•з”Ёе°ҶжҲҗдёәжҜҸдёӘе·ҘдҪңж ‘пјҢжІЎжңүзү№ж®ҠеӨ„зҗҶгҖӮ дёҚе№ёзҡ„жҳҜпјҢ`refs/rewritten`еңЁ`refs/worktree`д№ӢеүҚеҮәзҺ°дәҶпјҢжүҖд»ҘиҝҷжҳҜжҲ‘们иғҪеҒҡзҡ„е…ЁйғЁеҶ…е®№гҖӮ
```
在Git 2.24(2019年第4季度)中,"git rebase --rebase-merges
"学会了使用不同的合并策略并向它们传递特定于策略的选项。
请查看 476998d 提交记录(2019年9月4日),作者为Elijah Newren (newren
)。
请查看e1fac53 提交记录, a63f990 提交记录, 5dcdd74 提交记录, e145d99 提交记录, 4e6023b 提交记录, f67336d 提交记录, a9c7107 提交记录, b8c6f24 提交记录, d51b771 提交记录, c248d32 提交记录, 8c1e240 提交记录, 5efed0e 提交记录, 68b54f6 提交记录, 2e7bbac 提交记录, 6180b20 提交记录, d5b581f 提交记录(2019年7月31日),作者为Johannes Schindelin (dscho
)。
(由Junio C Hamano -- gitster
--于917a319 提交记录中合并,2019年9月18日)
随着 Git 2.25(2020 年第一季度)的推出,用于区分工作树本地引用和仓库全局引用的逻辑已得到修复,以便更好地实现保留合并。
请查看 提交 f45f88b, 提交 c72fc40, 提交 8a64881, 提交 7cb8c92, 提交 e536b1f (2019年10月21日) 由 SZEDER Gábor (szeder
) 提交。
(由 Junio C Hamano -- gitster
-- 合并于 提交 db806d7, 2019年11月10日)
path.c
:在trie_find()
中不要调用没有值的match
函数
签名作者:SZEDER Gábor
'logs/refs' 不���一个工作树特定的路径,但自从
commit b9317d55a3(确保 refs/rewritten/ 是每个工作树专用的,2019-03-07,v2.22.0-rc0)以来,'
git rev-parse --git-path
' 如果存在尾随 '
/
',就会返回虚假路径:
$ git -C WT/ rev-parse --git-path logs/refs --git-path logs/refs/
/home/szeder/src/git/.git/logs/refs
/home/szeder/src/git/.git/worktrees/WT/logs/refs/
我们使用
trie
数据结构来高效地确定路径是否属于公共目录或工作树特定。
正如
b9317d55a3 触发了一个与
trie
实现本身一样古老的 bug,该实现在
4e09cf2acf 中添加("
path
: optimize common dir checking",2015-08-31,Git v2.7.0-rc0 --
merge 列在
batch #2 中)。
根据描述
trie_find()
的注释,它只应为 trie 包含值的键的 "/-or-\0 结尾前缀" 调用给定的匹配函数 'fn'。
这是不正确的:有三个地方调用了 trie_find() 的匹配函数,但其中一个缺少了对值存在性的检查。
b9317d55a3 添加了两个新键到
trie
:
- '
logs/refs/rewritten
',和
- '
logs/refs/worktree
',
紧挨着已经存在的 '
logs/refs/bisect
'。
这导致了一个路径为 '
logs/refs/
' 的
trie
节点,它以前不存在,并且没有附加值。查询 '
logs/refs/
' 会找到此节点,然后命中那个不检查值存在性的匹配函数调用,从而使用
NULL
作为值调用匹配函数。
当使用
NULL
值调用
check_common()
匹配函数时,它返回 0,表示查询的路径不属于公共目录,最终导致上面显示的虚假路径。
将缺失的条件添加到
trie_find()
中,使其永远不会使用不存在的值调用匹配函数。
check_common()
将不再需要检查是否获得了非空值,因此删除该条件。
我相信没有其他路径会导致类似的虚假输出。
据我所知,导致匹配函数使用
NULL
值调用的唯一其他键是 '
co
'(由于键 '
common
' 和 '
config
'),但是,由于它们不在属于公共目录的目录中,因此预期结果是工作树特定路径。
请确保使用 Git 2.34 (Q4 2021) 版本,以避免内存泄漏问题。
请查看 提交 6e65854、提交 0c52cf8(2021年10月13日)和提交 e5a917f(2021年10月7日),作者是Ævar Arnfjörð Bjarmason (avar
)。
请查看提交 9d05b45(2021年10月7日),作者是Junio C Hamano (gitster
)。
(已于2021年10月25日由Junio C Hamano -- gitster
--合并到提交 bfa646c中)
序列控制器
:修复do_reset()
中的内存泄漏问题
签名作者:Ævar Arnfjörð Bjarmason
修复一个内存泄漏问题,该问题是在
9055e40("
sequencer
: introduce new commands to reset the revision",2018-04-25,Git v2.18.0-rc0 --
merge listed in
batch #6)中引入的,该问题调用了
setup_unpack_trees_porcelain()
但没有相应地调用
clear_unpack_trees_porcelain()
。
Git 2.41(2023年第二季度)简化了--rebase-merges
命令行选项处理,并引入了rebase.merges
配置变量。
请查看 提交 6605fb7, 提交 33561f5, 提交 7e5dcec (2023年3月25日) 由 Alex Henrie (alexhenrie
) 提交。
(由 Junio C Hamano -- gitster
-- 合并于 提交 9142fce, 2023年4月4日)
rebase
:添加一个配置选项用于--rebase-merges
签名作者:Alex Henrie
新选项的目的是为了满足那些希望默认开启
--rebase-merges
并且未来版本中可以轻松开启
--rebase-merges
而无需配置的用户需求。
将新选项命名为
rebase.rebaseMerges
,即使有点冗余,但与命令行选项的名称保持一致,并在
.gitconfig
的
[rebase]
部分中滚动值时清晰明了。
支持将
rebase.rebaseMerges
设置为非特定值"
true
",以满足不需要或不想了解rebase-cousins和no-rebase-cousins之间区别的用户需求。
在命令行上使用没有参数的
--rebase-merges
将覆盖配置中
rebase.rebaseMerges
的任何值,以保持与其他具有可选参数和相关配置选项的命令行标志的一致性。
git config
现在在其man页面中包括:
rebase.rebaseMerges
是否以及如何默认设置--rebase-merges
选项。可以是rebase-cousins
,no-rebase-cousins
或布尔值。将其设置为true或no-rebase-cousins
等同于--rebase-merges=no-rebase-cousins
,将其设置为rebase-cousins
等同于--rebase-merges=rebase-cousins
,将其设置为false等同于--no-rebase-merges
。
在命令行上传递--rebase-merges
,带或不带参数,会覆盖任何rebase.rebaseMerges
配置。
git rebase
现在在其手册页面中包括以下内容:
撤销rebase.rebaseMerges
配置选项和先前的--rebase-merges
。
rebase-merges
已被删除,并将导致许多不同的fatal:
消息,具体取决于您如何遇到该选项。存在边缘情况。Visual Studio尚未注意到,特别是对于git pull
配置选项。 - Philip Oakley--preserve-merges
已经被移除了? - ak2