Git
英语 ▾ 主题 ▾ 最新版本 ▾ git-merge-tree 最后更新于 2.46.0

名称

git-merge-tree - 在不触碰索引或工作树的情况下执行合并

概要

git merge-tree [--write-tree] [<options>] <branch1> <branch2>
git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2> (deprecated)

描述

此命令具有现代的 --write-tree 模式和已弃用的 --trivial-merge 模式。除了最后的 已弃用描述 部分,本文档的其余部分都描述了现代的 --write-tree 模式。

执行合并,但不创建任何新提交,也不读取或写入工作树或索引。

执行的合并将使用与“真实” git-merge[1] 相同的功能,包括

  • 单个文件的 3 路内容合并

  • 重命名检测

  • 适当的目录/文件冲突处理

  • 递归祖先合并(即,当存在多个合并基础时,通过合并合并基础来创建虚拟合并基础)

  • 等等。

合并完成后,将创建一个新的顶级树对象。有关详细信息,请参阅下面的 输出 部分。

选项

-z

不要在 <冲突文件信息> 部分中引用文件名,并以 NUL 字符而不是换行符结束每个文件名。还以 NUL 字符而不是换行符开头消息部分。有关更多信息,请参阅下面的 输出 部分。

--name-only

在冲突文件信息部分,不要为冲突文件输出 (mode, oid, stage, path) 元组列表,而只提供一个包含冲突文件名的列表(如果文件名有多个冲突阶段,则不要多次列出文件名)。

--[no-]messages

将任何信息消息(如“自动合并 <路径>”或 CONFLICT 通知)写入 stdout 的末尾。如果未指定,默认情况下如果存在合并冲突,则包含这些消息,否则省略它们。

--allow-unrelated-histories

默认情况下,如果指定的两个分支没有共同的历史记录,merge-tree 会报错。可以使用此标志覆盖此检查,使合并继续进行。

--merge-base=<tree-ish>

不要为 <branch1> 和 <branch2> 查找合并基础,而是为合并指定一个合并基础,目前不支持指定多个基础。此选项与 --stdin 不兼容。

由于直接提供了合并基础,因此 <branch1> 和 <branch2> 不需要指定提交;树就足够了。

-X<option>
--strategy-option=<option>

将合并策略特定的选项传递给合并策略。有关详细信息,请参阅 git-merge[1]

输出

对于成功的合并,git-merge-tree 的输出只是一行

<OID of toplevel tree>

而对于有冲突的合并,默认情况下输出格式如下

<OID of toplevel tree>
<Conflicted file info>
<Informational messages>

这些将在下面分别讨论。

但是,有一个例外。如果传递了 --stdin,则在开头有一个额外的部分,结尾有一个 NUL 字符,然后每个输入行都会重复所有部分。因此,如果第一次合并有冲突,而第二次合并干净,则输出格式将如下所示

<Merge status>
<OID of toplevel tree>
<Conflicted file info>
<Informational messages>
NUL
<Merge status>
<OID of toplevel tree>
NUL

合并状态

这是一个整数状态,后跟一个 NUL 字符。整数状态为

   0: merge had conflicts
   1: merge was clean
   <0: something prevented the merge from running (e.g. access to repository
objects denied by filesystem)

顶级树的 OID

这是一个树对象,表示在 git merge 结束时将在工作树中签出的内容。如果有冲突,则此树中的文件可能包含嵌入的冲突标记。此部分后面始终是一个换行符(如果传递了 -z,则为 NUL 字符)。

冲突文件信息

这是一个包含以下格式的行的序列

<mode> <object> <stage> <filename>

文件名将按配置变量 core.quotePath 所解释的方式引用(请参阅 git-config[1])。但是,如果传递了 --name-only 选项,则会省略模式、对象和阶段。如果传递了 -z,则“行”以 NUL 字符而不是换行符结束。

信息消息

此部分提供信息消息,通常是关于冲突的。此部分的格式根据是否传递 -z 而有很大差异。

如果传递了 -z

输出格式为零个或多个冲突信息记录,每个记录的格式为

<list-of-paths><conflict-type>NUL<conflict-message>NUL

其中 <路径列表> 的格式为

<number-of-paths>NUL<path1>NUL<path2>NUL...<pathN>NUL

并且包括受 <冲突消息> 中的冲突或信息消息影响的路径(或分支名称)。此外,<冲突类型> 是一个稳定的字符串,解释了冲突的类型,例如

  • "自动合并"

  • "冲突 (rename/delete)"

  • "冲突 (submodule 缺少合并基础)"

  • "冲突 (二进制)"

而 <冲突消息> 是关于冲突的更详细的消息,通常(但并非总是)在其内嵌入 <稳定简短类型描述>。这些字符串可能会在将来的 Git 版本中发生变化。一些示例

  • "自动合并 <文件>"

  • "冲突 (rename/delete):<旧文件> 重命名…​但在…​中被删除"

  • "无法合并子模块 <子模块>(没有合并基础)"

  • "警告:无法合并二进制文件:<文件名>"

如果未传递 -z

此部分以空行开头,将其与前面的部分隔开,然后只包含前面部分的 <冲突消息> 信息(以换行符隔开)。这些是非稳定字符串,脚本不应该对其进行解析,它们只是为了人类阅读。此外,请注意,虽然 <冲突消息> 字符串通常不包含嵌入的换行符,但有时会包含。 (但是,自由格式的消息永远不会包含嵌入的 NUL 字符)。因此,整个信息块是为了人类读者作为所有冲突消息的集合。

退出状态

对于成功的、无冲突的合并,退出状态为 0。当合并有冲突时,退出状态为 1。如果由于某种错误而无法完成(或开始)合并,则退出状态将不是 0 或 1(并且输出是未指定的)。当传递 --stdin 时,对于成功和有冲突的合并,返回状态都为 0,如果无法完成所有请求的合并,则返回状态将不是 0 或 1。

使用说明

此命令旨在用作低级管道,类似于 git-hash-object[1]git-mktree[1]git-commit-tree[1]git-write-tree[1]git-update-ref[1]git-mktag[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

请注意,当退出状态非零时,此序列中的 NEWTREE 将包含比仅一个树更多的输出。

对于冲突,输出将包含与使用 git-merge[1] 相同的信息

输入格式

git merge-tree --stdin 输入格式完全基于文本。每行的格式如下

[<base-commit> -- ]<branch1> <branch2>

如果一行以 -- 分隔,则分隔符之前的字符串用于指定合并的合并基础,分隔符之后的字符串描述要合并的分支。

应避免的错误

不要查看生成的顶级树以尝试查找哪些文件有冲突;而是解析 冲突文件信息 部分。解析整个树不仅在大型存储库中速度会非常慢,而且还有许多类型的冲突无法通过冲突标记表示(修改/删除、模式冲突、两侧都修改的二进制文件、文件/目录冲突、各种重命名冲突排列等)。

不要将空的 冲突文件信息 列表解释为干净的合并;检查退出状态。合并可能存在冲突,而没有单个文件冲突(有几种类型的目录重命名冲突属于此类,并且将来可能会添加其他类型)。

不要尝试从 冲突文件信息 列表中猜测或让用户猜测冲突类型。那里的信息不足以做到这一点。例如:重命名/重命名(1到2) 冲突(双方以不同的方式重命名了同一个文件)将导致三个不同的文件具有更高阶的阶段(但每个文件只有一个更高阶的阶段),无法(除了 信息消息 部分)确定这三个文件是相关的。文件/目录冲突也会导致一个文件只有一个更高阶的阶段。可能参与目录重命名冲突(当“merge.directoryRenames”未设置或设置为“conflicts”时)也会导致一个文件只有一个更高阶的阶段。在所有情况下,信息消息 部分包含必要的详细信息,尽管它不是为机器解析而设计的。

不要假设 冲突文件信息 中的每条路径和 信息消息 中的逻辑冲突都有一对一的映射,也不要假设存在一对多映射或多对一映射。存在多对多映射,这意味着每条路径在一个合并中可以有多种逻辑冲突类型,每种逻辑冲突类型可以影响多条路径。

不要假设 信息消息 部分中列出的所有文件名都存在冲突。可以包含没有冲突的文件的消息,例如“自动合并 <文件>”。

避免从 冲突文件信息 中获取 OID 并重新合并它们以向用户展示冲突。这将丢失信息。相反,查找在 顶层树的 OID 中找到的文件版本并显示它。特别是,后者将包含用原始分支/提交注释的冲突标记,以及在涉及重命名的情况下,原始文件名。虽然您可以在重新合并时在冲突标记注释中包含原始分支/提交,但原始文件名无法从 冲突文件信息 中获得,因此您将丢失可能有助于用户解决冲突的信息。

已弃用描述

根据 描述,与本文档的其余部分不同,本节描述已弃用的 --trivial-merge 模式。

除了可选的 --trivial-merge 外,此模式不接受任何选项。

此模式读取三个树状,并以半差异格式将平凡合并结果和冲突阶段输出到标准输出。由于它是为更高级别的脚本设计用于使用和将结果合并回索引的,因此它省略了与 <branch1> 匹配的条目。第二种形式的结果类似于三路 git read-tree -m 的结果,但它不是将结果存储在索引中,而是将条目输出到标准输出。

这种形式不仅适用范围有限(平凡合并无法处理单个文件的合并、重命名检测、正确的目录/文件冲突处理等),其输出格式也很难使用,并且它通常比第一种形式的性能更差,即使是在成功的合并中也是如此(尤其是在大型存储库中)。

GIT

git[1] 套件的一部分

scroll-to-top