Skip to content

git-merge-tree

在不接触索引或工作树的情况下执行合并。

概要

txt
'git merge-tree' [--write-tree] [<options>] <branch1> <branch2>
'git merge-tree' [--trivial-merge] <base-tree> <branch1> <branch2> (已弃用)

描述

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

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

执行的合并将使用与"真正的" git-merge(1) 相同的功能,包括:

  • 单个文件的三方内容合并
  • 重命名检测
  • 正确的目录/文件冲突处理
  • 递归祖先合并(即当有多个合并基础时,通过合并合并基础创建虚拟合并基础)
  • 等等。

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

选项

--stdin

:从标准输入读取要合并的提交,而不是从命令行。有关更多信息,请参阅下面的输入格式。隐含 -z

-z

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

--name-only

:在冲突文件信息部分中,不是为冲突文件输出(模式、oid、阶段、路径)元组列表,而只提供有冲突的文件名列表(如果文件名有多个冲突阶段则不重复列出)。

--messages, --no-messages

将任何信息性消息(如 "Auto-merging <path>" 或 CONFLICT 通知)写入标准输出末尾。如果未指定,默认在有合并冲突时包含这些消息,否则省略它们。

--quiet

:禁用程序的所有输出。当您只对退出状态感兴趣时很有用。允许 merge-tree 在发现冲突时提前退出,并允许它避免写入合并创建的大部分对象。

--allow-unrelated-histories

:如果指定的两个分支没有共同历史,merge-tree 默认会报错。可以给出此标志来覆盖该检查并使合并继续进行。

--merge-base=<tree-ish>

:不是为 <branch1> 和 <branch2> 查找合并基础,而是为合并指定一个合并基础。此选项与 --stdin 不兼容。 目前不支持指定多个基础,这意味着当合并具有多个合并基础的两个分支时,使用此选项可能导致合并结果与 git merge 计算的结果不同。这可能包括在结果合并中丢失历史某一方所做的某些更改。 使用此选项时,由于直接提供了合并基础,<branch1> 和 <branch2> 不需要指定提交;树就足够了。

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

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

输出

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

&lt;顶级树的 OID&gt;

而对于有冲突的合并,输出默认为以下形式:

&lt;顶级树的 OID&gt;
&lt;冲突文件信息&gt;
&lt;信息性消息&gt;

下面分别讨论这些内容。

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

&lt;合并状态&gt;
&lt;顶级树的 OID&gt;
&lt;冲突文件信息&gt;
&lt;信息性消息&gt;
NUL
&lt;合并状态&gt;
&lt;顶级树的 OID&gt;
NUL

合并状态

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

 0:合并有冲突
 1:合并是干净的

顶级树的 OID

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

冲突文件信息

这是格式为 <mode> <object> <stage> <filename> 的行序列。

文件名将按配置变量 core.quotePath 的说明引用(参见 git-config(1))。但是,如果传递了 --name-only 选项,则省略模式、对象和阶段。如果传递了 -z,则"行"以 NUL 字符而不是换行符终止。

信息性消息

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

如果传递了 -z

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

&lt;路径列表&gt;&lt;冲突类型&gt;NUL&lt;冲突消息&gt;NUL

其中 <路径列表> 格式为

&lt;路径数量&gt;NUL&lt;path1&gt;NUL&lt;path2&gt;NUL...&lt;pathN&gt;NUL

并包含受 <conflict-message> 中的冲突或信息性消息影响的路径(或分支名称)。此外,<conflict-type> 是解释冲突类型的稳定字符串,例如

  • "Auto-merging"
  • "CONFLICT (rename/delete)"
  • "CONFLICT (submodule lacks merge base)"
  • "CONFLICT (binary)"

而 <conflict-message> 是关于冲突的更详细消息,通常(但不总是)在其中嵌入 <stable-short-type-description>。这些字符串可能在未来的 Git 版本中更改。一些示例:

  • "Auto-merging <file>"
  • "CONFLICT (rename/delete): <oldfile> renamed...but deleted in..."
  • "Failed to merge submodule <submodule> (no merge base)"
  • "Warning: cannot merge binary files: <filename>"

如果未传递 -z

此部分以空行开始以将其与前面的部分分开,然后仅包含来自上一部分的 <conflict-message> 信息(以换行符分隔)。这些是非稳定字符串,脚本不应解析,仅供人类使用。另请注意,虽然 <conflict-message> 字符串通常不包含嵌入的换行符,但有时会包含。(但是,自由格式的消息永远不会包含嵌入的 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)。因此,它可以用作一系列步骤的一部分,例如:

   vi message.txt
   BRANCH1=refs/heads/test
   BRANCH2=main
   NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2) || {
       echo "There were conflicts..." 1&gt;&2
       exit 1
   }
   NEWCOMMIT=$(git commit-tree $NEWTREE -F message.txt \
       -p $BRANCH1 -p $BRANCH2)
   git update-ref $BRANCH1 $NEWCOMMIT

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

对于冲突,输出包含与 git-merge(1) 相同的信息:

  • 将写入工作树的内容(顶级树的 OID)
  • 将写入索引的高阶阶段(冲突文件信息)
  • 将打印到标准输出的任何消息(信息性消息)

输入格式

'git merge-tree --stdin' 输入格式完全是基于文本的。每行格式为:

[&lt;base-commit&gt; -- ]&lt;branch1&gt; &lt;branch2&gt;

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

应避免的错误

不要查看结果顶级树以尝试查找哪些文件有冲突;而是解析冲突文件信息部分。不仅解析整个树在大型仓库中会极其缓慢,而且有许多类型的冲突无法用冲突标记表示(修改/删除、模式冲突、双方都更改了二进制文件、文件/目录冲突、各种重命名冲突排列等)。

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

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

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

不要假设信息性消息部分中列出的所有文件名都有冲突。消息可以包含没有冲突的文件,例如 "Auto-merging <file>"。

避免从冲突文件信息中获取 OID 并重新合并它们以向用户呈现冲突。这将丢失信息。而是查找在顶级树的 OID 中找到的文件版本并显示它。特别是,后者将有标注了正在合并的原始分支/提交的冲突标记,如果涉及重命名,还会有原始文件名。虽然您可以在重新合并时在冲突标记注释中包含原始分支/提交,但原始文件名无法从冲突文件信息中获取,因此您将丢失可能帮助用户解决冲突的信息。

已弃用的描述

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

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

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

此形式不仅适用性有限(简单合并无法处理单个文件的内容合并、重命名检测、正确的目录/文件冲突处理等),输出格式也难以使用,即使在成功合并时通常也比第一种形式性能更差(特别是在大型仓库中工作时)。

Git

git(1) 套件的一部分

基于 CC BY-NC-SA 3.0 许可发布