lbergnehr在答案中提到的git merge-tree
,随着Git 2.38(2022年第3季度)的到来变得更加有效,因为“git merge-tree
”(手册)学会了一种新模式,在这种模式下它需要两个提交,并计算出如果合并这两个提交的历史记录,则将生成一个合并提交的树。
简介; git merge-tree
在 Git 2.38 (2022年第三季度) 刚刚变得非常棒
您可以快速测试两个分支是否可以合并(不进行实际合并,也就是说不修改分支、索引或工作树!):
NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2)
test $? -eq 0 || die "存在冲突..."
即使这些分支没有关联,您也可以这样做:
git merge-tree --write-tree --allow-unrelated-histories $BRANCH1 $BRANCH2
您可以列出有冲突的文件以及它们为什么会发生冲突:
git merge-tree --write-tree --no-messages branch1 branch2
您可以列出有冲突的文件(只列出文件名):
git merge-tree --write-tree --no-messages --name-only branch1 branch2
就像我之前所说的,非常令人印象深刻...
请查看提交 7260e87, 提交 7976721, 提交 7c48b27, 提交 de90581, 提交 cb26077, 提交 b520bc6, 提交 7fa3338, 提交 a4040cf, 提交 fae26ce, 提交 a1a7811, 提交 a34edae, 提交 1f0c3a2, 提交 6ec755a, 提交 55e48f6, 提交 70176b7 (2022年6月18日) 由Elijah Newren (newren
)提交。
请查看提交 2715e8a, 提交 6debb75 (2022年6月18日) 由Johannes Schindelin (dscho
)提交。
(由Junio C Hamano -- gitster
--合并于提交 be733e1, 2022年7月14日)
签名作者:Elijah Newren
这增加了执行真正的合并能力,而不仅仅是微不足道的合并(意味着处理三方内容合并、递归祖先合并、重命名、正确的目录/文件冲突处理等)。
然而,与
git merge
(man)不同,工作树和索引保持不变,没有分支被更新。
唯一的输出是:
- 标准输出打印的顶层结果树
- 退出状态为0(干净)、1(存在冲突)或其他任何值(无法执行合并;未知是否干净或有冲突)
此输出旨在由某些更高级别的脚本使用,例如以下步骤序列:
NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2)
test $? -eq 0 || die "There were conflicts..."
NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2)
git update-ref $BRANCH1 $NEWCOMMIT
请注意,更高级别的脚本可能还想访问通常在合并期间输出的冲突/警告消息,或者快速访问具有冲突的文件列表。
这也将合并树的传统微不足道的合并标记为已弃用。微不足道的合并不仅适用性有限,输出格式也难以处理(其格式未经记录),并且通常比真正的合并性能差。
git merge-tree
现在在其man page中包含以下内容:
git-merge-tree - 执行合并操作而不影响索引或工作树
git merge-tree
现在在其man page中包含以下内容:
'git merge-tree' [--write-tree]
'git merge-tree' [--trivial-merge] (已弃用)
git merge-tree
现在在其man page中包含以下内容:
该命令有现代的
--write-tree
模式和已弃用的
--trivial-merge
模式。除了末尾的
<<DEPMERGE,DEPRECATED DESCRIPTION>>
部分外,本文档的其余部分描述了现代的
--write-tree
模式。
执行合并操作,但不会创建任何新提交,并且不会读取或写入工作树或索引。
执行的合并将使用与“真实”
git merge
相同的功能,包括:
- 单个文件的三方内容合并
- 重命名检测
- 正确的目录/文件冲突处理
- 递归祖先合并(即当存在多个合并基时,通过合并合并基来创建虚拟合并基)
- 等等
合并完成后,将创建一个新的顶级树对象。有关详细信息,请参见下面的
OUTPUT
。
对于成功或有冲突的合并,git-merge-tree的输出只有一行:
<OID of toplevel tree>
。打印的树对象对应于在
git merge
结束时将在工作树中检出的内容,因此可能包含带有冲突标记的文件。
对于成功的非冲突合并,退出状态为0。当合并存在冲突时,退出状态为1。如果由于某种错误而无法完成(或开始)合并,则退出状态为0或1以外的其他值(输出未指定)。
此命令旨在作为低级别的管道工具使用,类似于
git hash-object
、
git mktree
、
git commit-tree
、
git write-tree
、
git update-ref
和
git mktag
。因此,它可以作为一系列步骤的一部分使用,例如:
NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2)
test $? -eq 0 || die "There were conflicts..."
NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2)
git update-ref $BRANCH1 $NEWCOMMIT
根据
<<NEWMERGE,DESCRIPTION>>
,与本文档的其余部分不同,此部分描述了已弃用的
--trivial-merge
模式。
除了可选的
--trivial-merge
之外,此模式不接受任何选项。
此模式读取三个树状物,并以半差异格式将平凡合并结果和冲突阶段输出到标准输出。由于这是为更高级别的脚本消耗和将结果合并回索引而设计的,因此它省略了与
<branch1>
匹配的条目。
这种形式不仅适用性有限(平凡合并无法处理单个文件的内容合并、重命名检测、正确的目录/文件冲突处理等),输出格式也难以处理,并且即使在成功合并时(尤其是在大型存储库中工作时),它的性能通常也会比第一种形式差。
您可以避免最后的信息提示:
签名:Elijah Newren
运行
git merge-tree --write-tree
(man) 时,我们以前只返回反映合并干净程度的退出状态,并打印出结果合并的顶层树。
合并还有信息性消息,例如:
- "
Auto-merging <PATH>
"
- "
CONFLICT (content): ...
"
- "
CONFLICT (file/directory)
"
- 等等。
事实上,当发生非内容冲突(例如
file/directory
、
modify/delete
、
add/add
具有不同模式、
rename/rename (1to2)
等)时,这些信息性消息可能是用户唯一得到的通知,因为这些冲突在文件内容中无法表示。
添加一个
--[no-]messages
选项,以便调用者可以请求在输出末尾包含这些消息。
默认情况下,在存在冲突时包含此类消息,在合并干净时默认情况下省略它们。
git merge-tree
现在在其手册页中包括以下内容:
选项
--[no-]messages
将任何信息性消息(如“自动合并<路径>
”或冲突通知)写入标准输出的末尾。
如果未指定,则默认情况下,如果存在合并冲突,则包括这些消息,否则将省略它们。
对于成功的合并,git-merge-tree的输出只是一行:
<顶层树的OID>
而对于有冲突的合并,默认情况下输出形式为:
git merge-tree
现在在其手册页中包括以上内容:
顶级树的 OID
这是一个树对象,代表在 `git merge` 结束时在工作树中将被检出的内容。
如果存在冲突,则此树中的文件可能会包含嵌入式冲突标记。
信息性消息
此部分始终以空行开头,与前一部分分隔开,并包含有关合并的自由形式消息,例如:
- "
正在自动合并 <file>
"
- "
CONFLICT (rename/delete): <oldfile> 重命名...但在删除时已删除...
"
- "
无法合并子模块 <submodule> (<reason>)
"
- "
警告:无法合并二进制文件:<filename>
"
如果你想知道哪些文件有冲突以及原因,使用之前的--no-messages
选项!
git merge-tree --write-tree --no-messages branch1 branch2
^^^^^^^^^^^^^
签名作者:Elijah Newren
git merge-tree
(man) 的调用者
--write-tree
通常想知道哪些文件存在冲突。
虽然他们可能尝试解析打印的 CONFLICT 通知,但这些消息并不适合机器阅读。
在自由格式消息之前提供一个更简单的机制,只需以与
git ls-files
(man) 相同的格式(带引号,但仅限于未合并的文件)在输出中打印文件即可。
git merge-tree
现在在其手册页面中包含了:
Conflicted file list
This is a sequence of lines containing a filename on each line, quoted
as explained for the configuration variable `core.quotePath` (see
[`git config`](https://git-scm.com/docs/git-config)).
如果你想知道有冲突的文件列表(不包括原因,只有文件名),请使用新的--name-only
选项!
git merge-tree --write-tree --name-only --no-messages branch1 branch2
^^^^^^^^^^^
merge-tree
:提供方便访问 ls-files -u
样式信息的方法
签名:Elijah Newren
Much like git merge
(man) updates the index with information of the form
(mode, oid, stage, name)
provide this output for conflicted files for merge-tree as well.
Provide a --name-only
option for users to exclude the mode, oid, and stage and only get the list of conflicted filenames.
git merge-tree
现在在其手册页面中包含:
--name-only
在冲突文件信息部分,不再输出(模式、oid、阶段、路径)元组列表以提供有冲突的文件列表,而是仅提供具有冲突的文件名列表(如果它们具有多个冲突阶段,则不要多次列出文件名)。
git merge-tree
现在在其手册页面中包含:
这是一个带有格式的行序列。
文件名将被引用为配置变量
core.quotePath
中所解释的方式(参见
git config
)。
但是,如果传递了
--name-only
选项,则模式、对象和阶段将被省略。
即使您的两个分支没有共同祖先(不相关的历史记录/历史记录),也可以这样做!
git merge-tree --write-tree --allow-unrelated-histories --name-only --no-messages branch1 branch2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
merge-tree
:添加 --allow-unrelated-histories 标志
签署者:Elijah Newren
人们可能想要合并没有共同祖先的历史记录;提供一个与 git merge
(man) 使用相同名称的标志来允许此操作。
git merge-tree
现在在其手册页面中包含了这一内容:
--allow-unrelated-histories
默认情况下,如果指定的两个分支没有共同的历史记录,merge-tree 将会报错。
可以使用此标志来覆盖该检查并使合并继续进行。
在 Git 2.39 (Q4 2022) 中, "
git merge-tree --stdin
"
(man) 是一种新的请求合并系列和报告合并结果的方式。
请查看提交 ec1edbc,提交 a9f5bb8(2022年10月23日),由Elijah Newren (newren
)提交。
(由Taylor Blau -- ttaylorr
--合并于提交 b1e3dd6,2022年10月30日)
merge-tree
:支持使用--stdin进行多次批处理合并
签名作者:Elijah Newren
新增一个选项--stdin
给merge-tree
,它将接受每行两个需要合并的分支输入,并逐个执行所有合并操作并输出结果。此选项会隐含-z
,并修改输出结果以包括合并状态,因为现在涉及到多次合并,程序的退出码不能再传达这些信息。
例如,对于Git托管提供者而言,这可能非常有用。当一个分支被更新时,可能需要检查针对该分支的所有代码审查是否仍然可以清晰地合并。如果在具有许多代码审查的存储库中避免为每个代码审查启动单独的进程,可能会节省大量开销。
git merge-tree
现在在其手册页面中包含了:
如果传递了
--stdin
,则在开头会有一个额外的部分,在结尾处有一个NUL字符,然后所有部分都会为每个输入行重复。因此,如果第一个合并冲突而第二个干净,则输出将采用以下形式:
<合并状态>
<顶层树的OID>
<冲突文件信息>
<信息性消息>
NUL
<合并状态>
<顶层树的OID>
NUL
合并状态
这是一个整数状态,后面跟着一个NUL字符。
整数状态为:
0
:合并存在冲突
1
:合并干净
<0
:某些原因阻止了合并运行
(例如,文件系统拒绝访问存储库对象)
git merge-tree
现在在其手册页面中包含:
除0或1以外的其他内容(输出未指定)。
当传递--stdin
时,返回状态为
- 对于成功和冲突的合并都为0,并且
- 如果无法完成所有请求的合并,则为除0或1以外的其他内容。
git merge-tree
的参考资料 链接,但我不确定如何在这种情况下使用它。您是否可以接受修改工作树或索引,还是希望它完全没有副作用,或者其他什么? - Daniel Hrefs/pull/$prnumber/merge
(尽管我认为这种行为不再是 API 的一部分,他们可能会更改它)。检出另一个分支会起作用,但会搞乱HEAD
,如果您没有裸仓库,则会搞乱工作树。您可以使用git worktree
来解决这个问题。 - Daniel H