非常教程

Git参考手册

分支和合并 | Branching and Merging

git merge

名称

git-merge - Join two or more development histories together

概要

git merge [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
        [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
        [--[no-]allow-unrelated-histories]
        [--[no-]rerere-autoupdate] [-m <msg>] [<commit>…​]
git merge --abort
git merge --continue

描述

将已命名的提交(从历史记录与当前分支分离的时间以来)的更改合并到当前分支中。该命令用于git pull合并另一个存储库中的更改,并可用于手动合并从一个分支到另一个分支的更改。

假设存在以下历史记录,并且当前分支是“ master”:

          A---B---C topic
         /
    D---E---F---G master

然后“ git merge topic”将重播在topic分支上发生的变化,因为它从master(即E)分支到其当前的commit(C)之上master,并且将结果记录在新的提交中以及两个父提交的名称和日志消息来自描述更改的用户。

          A---B---C topic
         /         \
    D---E---F---G---H master

第二个语法(“ git merge --abort”)只能在合并导致冲突后才能运行。git merge --abort将中止合并过程并尝试重新构建合并前状态。但是,如果在合并开始时发生未提交的更改(尤其是在合并开始后进一步修改这些更改),git merge --abort则在某些情况下将无法重建原始(合并前)更改。因此:

警告git merge不鼓励使用不平凡的未提交更改:尽管可能,但可能会让您处于难以在冲突情况下退出的状态。

第四种语法(“ git merge --continue”)只能在合并导致冲突后才能运行。

选项

--commit --no-commit

执行合并并提交结果。这个选项可以用来覆盖--no-commit。

使用--no-commit执行合并,但假装合并失败并且不自动提交,以使用户有机会在提交之前检查并进一步调整合并结果。

--edit -e --no-edit

在提交成功的机械合并之前调用编辑器来进一步编辑自动生成的合并消息,以便用户可以解释并验证合并。该--no-edit选项可用于接受自动生成的消息(这通常是不鼓励的)。该--edit(或-e)选项仍然是有用的,如果你给同一个消息草稿-m命令行选项,并希望在编辑器中编辑。

较旧的脚本可能取决于不允许用户编辑合并日志消息的历史行为。他们将在运行时看到编辑器打开git merge。为了更容易地将这些脚本调整为更新的行为,GIT_MERGE_AUTOEDIT可以将环境变量设置为no它们的开头。

--ff

当合并解析为快进时,只更新分支指针,而不创建合并提交。这是默认行为。

--no-ff

即使合并解析为快进,也可以创建合并提交。这是合并注释(可能有符号)标记时的默认行为。

--ff-only

拒绝合并并以非零状态退出,除非电流HEAD已经是最新的或合并可以解决为快进。

--log=<n> --no-log

除了分支名称之外,还可以用来自至多<n>实际提交的单行描述来填充日志消息。另请参阅git-fmt-merge-msg [1]。

使用--no-log不会列出要合并的实际提交的单行描述。

--stat -n --no-stat

在合并结束时显示diffstat。diffstat也由配置选项merge.stat控制。

使用-n或--no-stat不会在合并结束时显示diffstat。

--squash --no-squash

生成工作树和索引状态,就像发生真正的合并(合并信息除外)一样,但实际上并未进行提交,移动HEAD或记录$GIT_DIR/MERGE_HEAD(以导致下一个git commit命令创建合并提交)。这允许您在当前分支上创建一个单独的提交,其效果与合并另一个分支相同(或者在章鱼的情况下更多)。

用--no-squash执行合并并提交结果。这个选项可以用来覆盖--squash。

-s <strategy> --strategy=<strategy>

使用给定的合并策略; 可以多次提供,以按照他们应该尝试的顺序指定它们。如果没有-s选项,则使用内置策略列表(否则git merge-recursive合并单个头部时git merge-octopus)。

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

将合并策略特定选项传递给合并策略。

--verify-signatures --no-verify-signatures

验证被合并的分支的提示提交是否使用有效密钥签名,即具有有效uid的密钥:在默认信任模型中,这意味着签名密钥已由可信密钥签名。如果侧分支的提示提交未使用有效密钥进行签名,则会中止合并。

--summary --no-summary

同义词--stat和--no-stat; 这些已被弃用,并将在未来被删除。

-q --quiet

安静地操作。意味着 --no-progress

-v --verbose

详细。

--progress --no-progress

明确地打开/关闭进度。如果没有指定,如果标准错误连接到终端,则显示进度。请注意,并非所有合并策略都可能支持进度报告。

--allow-unrelated-histories

默认情况下,git merge命令拒绝合并不共享祖先的历史记录。在合并两个独立开始他们的生活的项目的历史时,可以使用此选项来覆盖此安全性。由于这是非常罕见的情况,因此默认情况下不存在配置变量,因此不会添加该变量。

-S<keyid> --gpg-sign=<keyid>

GPG-sign合并提交。该keyid参数是可选的,并且默认为提交者身份; 如果指定,它必须粘贴到选项没有空格。

-m <msg>

设置要用于合并提交的提交消息(以防创建)。

如果--log指定,则将合并的提交短记录附加到指定的消息。

git fmt-merge-msg命令可用于为自动git merge调用提供良好的默认值。自动化消息可以包含分支描述。

--no-rerere-autoupdate

如果可能的话,允许rerere机制用自动冲突解决的结果更新索引。

--abort

中止当前的冲突解决过程,并尝试重新构建预合并状态。

如果在合并开始时存在未提交的工作树更改,git merge --abort则在某些情况下无法重建这些更改。因此建议在运行之前始终提交或存储更改git merge

git merge --abort相当于git reset --merge何时MERGE_HEAD存在。

--continue

git merge由于冲突停止后,您可以通过运行来结束合并git merge --continue(请参阅下面的“如何解决冲突”一节)。

<commit>…​

通常,其他分行负责人将合并到我们的分行。指定多个提交将与两个以上的父母创建合并(亲切地称为Octopus合并)。

如果没有从命令行提交提交,则合并当前分支被配置为用作其上游的远程跟踪分支。另见本手册页面的配置部分。

FETCH_HEAD(并且没有其他提交)被指定时,.git/FETCH_HEAD通过先前调用git fetch合并记录在文件中的分支被合并到当前分支。

Pre-merge checks

在应用外部变更之前,您应该完成自己的工作,并在本地承诺,因此如果发生冲突,它不会被破坏。另见git-stash [1]。git pullgit merge会停止,而不做任何事情时,本地提交的更改与文件重叠git pull/ git merge可能需要更新。

为了避免在合并提交中记录不相关的更改,git pull并且git merge如果在索引中相对于HEAD提交注册了任何更改,也会中止。(一个例外是当已更改的索引条目处于已经合并的状态时。)

如果所有已命名的提交都已经是祖先HEADgit merge则会提前退出,并显示“已更新”消息。

Fast-forward merge

通常当前分支头是命名提交的祖先。这是最常见的情况,特别是在从git pull以下情况调用时:您正在跟踪上游存储库,您没有提交本地更改,现在您想更新为更新的上游修订版。在这种情况下,不需要新的提交来存储组合的历史; 相反,HEAD(与索引一起)更新为指向指定的提交,而不创建额外的合并提交。

该行为可以通过该--no-ff选项进行抑制。

真正的合并

除了在快进合并中(见上文),要合并的分支必须通过合并提交绑定在一起,合并提交将它们都作为其父项。

提交一个合并版本来协调所有要合并的分支的更改,并将您的HEAD索引和工作树更新为它。只要不重叠,可以在工作树中进行修改; 更新将保留它们。

如果不清楚如何协调更改,则会发生以下情况:

  1. HEAD指针保持不变。
  2. MERGE_HEADref被设置为指向另一个分支头。
  3. 干净合并的路径在索引文件和工作树中都会更新。
  4. 对于冲突的路径,索引文件最多可以记录三个版本:第1阶段存储公共祖先的版本,第2阶段的版本HEAD和第3 阶段的版本MERGE_HEAD(可以检查阶段git ls-files -u)。工作树文件包含“合并”程序的结果; 即3路合并结果与熟悉的冲突标记<<< === >>>
  5. 没有其他更改。特别是,在开始合并之前进行的本地修改将保持不变,并且它们的索引条目保持原样,即匹配HEAD

如果您尝试导致复杂冲突并想重新开始的合并,则可以使用恢复git merge --abort

Merging tag

合并注释(也可能是签名)标记时,即使可以进行快进合并,Git也会始终创建合并提交,并且提交消息模板是使用标记消息准备的。另外,如果标签已签名,则签名检查会作为消息模板中的注释报告。另请参阅git-tag [1]。

当您只想将导致正好被标记的提交的工作集成时,例如与上游发行版同步时,您可能不想进行不必要的合并提交。

在这种情况下,您可以在喂食之前自己“unwrap”标签git merge,或者--ff-only在您自己没有任何工作时通过。例如

git fetch origin
git merge v1.2.3^0
git merge --ff-only v1.2.3

如何呈现冲突

在合并期间,更新工作树文件以反映合并结果。在对共同祖先版本进行的更改中,不重叠的(即,您更改了文件的某个区域,而另一侧完全保留该区域,或反之亦然)最终结果逐字记录。但是,当双方都对同一地区进行更改时,Git不能随意选择一边而不是另一边,并要求您通过将双方对该区域的干涉解决。

默认情况下,Git使用与RCS套件中的“合并”程序使用的风格相同的风格来呈现这样一个冲突的大块,如下所示:

Here are lines that are either unchanged from the common
ancestor, or cleanly resolved because only one side changed.
<<<<<<< yours:sample.txt
Conflict resolution is hard;
let's go shopping.
=======
Git makes conflict resolution easy.
>>>>>>> theirs:sample.txt
And here is another line that is cleanly resolved or unmodified.

其中一对相互矛盾的变化发生的区域标有标记<<<<<<<=======>>>>>>>。之前的部分=======通常是你的一面,而之后的部分通常是他们的一面。

默认格式不显示原始在冲突区域中所说的内容。你不知道有多少行被删除, 取而代之的是芭比的评论在你身边。你唯一能说的是, 你的一方想说这是很难的, 你宁愿去购物, 而另一方想声称这是容易的。

通过将“merge.conflictStyle”配置变量设置为“diff3”,可以使用其他样式。在“diff3”风格中,上述冲突可能如下所示:

Here are lines that are either unchanged from the common
ancestor, or cleanly resolved because only one side changed.
<<<<<<< yours:sample.txt
Conflict resolution is hard;
let's go shopping.
|||||||
Conflict resolution is hard.
=======
Git makes conflict resolution easy.
>>>>>>> theirs:sample.txt
And here is another line that is cleanly resolved or unmodified.

除了<<<<<<<=======>>>>>>>标志,它使用另一个|||||||后跟原文标记。你可以说,原文只是陈述了一个事实,你方只是放弃了这个陈述而放弃了,而另一方则试图采取更积极的态度。有时您可以通过查看原件来获得更好的分辨率。

如何解决冲突

看到冲突后,你可以做两件事:

  • 决定不合并。您需要的唯一清理操作是将索引文件重置为HEAD提交以反向2.并清除由2.和3所做的工作树更改。git merge --abort可以用于此。
  • 解决冲突。Git将标记工作树中的冲突。将这些文件编辑为形状,git add并将其转换为索引。使用git commitgit merge --continue密封交易。后一个命令在调用之前检查是否存在正在进行的(中断的)合并git commit

您可以通过许多工具解决冲突:

  • 使用mergetool。git mergetool启动一个图形化的合并工具,这将通过合并工作。
  • 看看差异。git diff将显示三方差异,突出显示来自版本HEADMERGE_HEAD版本的更改。
  • 看看每个分支的差异。git log --merge -p <path>将首先显示HEAD版本和MERGE_HEAD版本的差异。
  • 看看原件。git show :1:filename显示共同的祖先,git show :2:filename显示HEAD版本,并git show :3:filename显示MERGE_HEAD版本。

例子

  • 合并分支fixesenhancements当前分支的顶部,使分支合并:$ git merge fixes enhancements
  • obsolete使用ours合并策略将分支合并到当前分支中:$ git merge -s我们的过时的
  • 将分支合并maint到当前分支中,但不要自动创建新的提交:$ git merge --no-commit maint

当您想要对合并进行进一步的更改,或者想要编写自己的合并提交消息时,可以使用此选项。

You should refrain from abusing this option to sneak substantial changes into a merge commit. Small fixups like bumping release/version name would be acceptable.

Merge strategies

合并机制(git mergegit pull命令)允许merge strategies使用-s选项选择后端。一些策略也可以采取他们自己的选择,这可以通过给出-X<option>参数git merge和/或通过git pull

resolve

这只能使用3路合并算法解析两个头(即当前分支和另一个分支)。它试图仔细检测交叉融合歧义,并被认为通常是安全和快速的。

recursive

这只能使用3路合并算法来解析两个头。当有多个可用于3路合并的共同祖先时,它将创建共同祖先的合并树并将其用作3路合并的参考树。据报道,这会导致更少的合并冲突,而不会因从Linux 2.6内核开发历史记录中进行的实际合并提交所做的测试而导致混淆。此外,这可以检测并处理涉及重命名的合并。这是拉取或合并一个分支时的默认合并策略。

recursive策略可以采取以下选择:

ours

该选项强制冲突的hunk通过支持our版本自动解决。来自另一棵与我们不冲突的树的变化反映到合并结果。对于二进制文件,整个内容都是从我们这边拿来的。

这不应与ours合并策略混淆,合并策略甚至不会考虑其他树包含的内容。它丢弃了其他树的所有内容,声明our历史包含发生在其中的所有事情。

theirs

这是相反的ours; 请注意,与此不同的ours是,没有theirs融合策略来混淆这个合并选项。

patience

使用此选项,merge-recursive花费一点额外的时间来避免由于不重要的匹配行(例如,来自不同功能的括号)而导致的混淆。当要合并的分支疯狂地分歧时使用它。另请参阅git-diff [1] --patience

diff-algorithm=patience|minimal|histogram|myers

告诉merge-recursive使用不同的差异算法,这可以帮助避免由于不重要的匹配行(例如不同功能的花括号)而发生误合。另请参阅git-diff [1] --diff-algorithm

ignore-space-change ignore-all-space ignore-space-at-eol

为了三路合并的目的,将指定类型的空白的行对待不变。空白变化与其他变化混合在一起不会被忽略。另见GIT-DIFF [1] ,-b-w--ignore-space-at-eol

  • If their version only introduces whitespace changes to a line, our version is used;
  • If our version introduces whitespace changes but their version includes a substantial change, their version is used;
  • Otherwise, the merge proceeds in the usual way.

renormalize

This runs a virtual check-out and check-in of all three stages of a file when resolving a three-way merge. This option is meant to be used when merging branches with different clean filters or end-of-line normalization rules. See "Merging branches with differing checkin/checkout attributes" in gitattributes[5] for details.

no-renormalize

禁用该renormalize选项。这覆盖merge.renormalize配置变量。

no-renames

关闭重命名检测。另请参阅git-diff [1] --no-renames

find-renames=<n>

打开重命名检测,可选择设置相似性阈值。这是默认设置。另请参阅git-diff [1] --find-renames

rename-threshold=<n>

Deprecated synonym for find-renames=<n>.

subtree=<path>

该选项是一种更高级的subtree策略形式,该策略可以猜测两个树在合并时必须如何移动以相互匹配。相反,指定的路径是前缀(或从开始剥离)以使两棵树的形状匹配。

octopus

这解决了两个以上负责人的情况,但拒绝执行需要手动解决的复杂合并。它主要用于将主题分支主题捆绑在一起。这是拉取或合并多个分支时的默认合并策略。

ours

这可以解析任意数量的头,但合并结果树始终是当前分支头的树,有效地忽略了所有其他分支的所有更改。它是用来取代侧枝的旧发展历史。请注意,这与recursive合并策略的-Xours选项不同。

subtree

这是一个修改后的递归策略。合并树A和B时,如果B对应于A的子树,则首先调整B以匹配A的树结构,而不是读取处于同一级别的树。这种调整也对共同的祖先树进行。

对于使用3路合并(包括默认值recursive)的策略,如果在两个分支上进行了更改,但稍后在其中一个分支上进行了恢复,则该更改将出现在合并结果中; 有些人觉得这种行为很混乱。这是因为在执行合并时仅考虑头部和合并基础,而不是个别提交。因此,合并算法将恢复的更改视为完全没有更改,而是替换更改后的版本。

配置

merge.conflictStyle

指定在合并时将冲突的区块写入工作树文件的样式。默认值是“合并”,它显示了一个<<<<<<<冲突标记,一侧=======发生的变化,一个标记,另一侧发生的变化,然后是>>>>>>>标记。另一种样式“diff3”在|||||||标记之前添加了一个标记和原始文本=======

merge.defaultToUpstream

如果在没有任何提交参数的情况下调用合并,则使用存储在其远程跟踪分支中的上次观察值合并为当前分支配置的上游分支。查询branch.<current branch>.merge名称为远程命名的远程分支的值branch.<current branch>.remote,然后将它们映射remote.<remote>.fetch到其对应的远程跟踪分支,并合并这些跟踪分支的提示。

merge.ff

默认情况下,Git在合并作为当前提交的后代的提交时不会创建额外的合并提交。相反,当前分支的尖端被快速转发。当设置为false,这个变量告诉Git在这种情况下创建一个额外的合并提交(相当于--no-ff从命令行提供选项)。设置only为时,只允许进行这种快进合并(相当于--ff-only从命令行提供选项)。

merge.branchdesc

除了分支名称之外,还可以使用与它们关联的分支描述文本填充日志消息。默认为false。

merge.log

除了分支名称之外,还可以在日志消息中最多填入要合并的实际提交中指定数量的单行描述。默认为false,true为20的同义词。

merge.renameLimit

在合并期间执行重命名检测时要考虑的文件数量; 如果未指定,则默认为diff.renameLimit的值。

merge.renormalize

告诉Git存储库中文件的规范表示已经随时间而改变(例如,较早的提交记录具有CRLF行尾的文本文件,但最近使用LF行结尾)。在这样的存储库中,Git可以在提交之前将提交中记录的数据转换为规范形式,然后再执行合并以减少不必要的冲突。有关更多信息,请参阅gitattributes [5]中的“合并具有不同签入/签出属性的分支”部分。

merge.stat

是否在合并结束时在ORIG_HEAD和合并结果之间打印diffstat。默认情况下为真。

merge.tool

控制哪个合并工具由git-mergetool [1]使用。下面的列表显示了有效的内置值。任何其他值都被视为自定义合并工具,并要求定义相应的mergetool。<tool> .cmd变量。

  • araxis
  • bc
  • bc3
  • codecompare
  • deltawalker
  • diffmerge
  • diffuse
  • ecmerge
  • emerge
  • examdiff
  • gvimdiff
  • gvimdiff2
  • gvimdiff3
  • kdiff3
  • meld
  • opendiff
  • p4merge
  • tkdiff
  • tortoisemerge
  • vimdiff
  • vimdiff2
  • vimdiff3
  • winmerge
  • xxdiff

merge.verbosity

控制递归合并策略显示的输出量。如果检测到冲突,级别0只输出最终的错误消息。1级只输出冲突,2个输出冲突和文件更改。5级及以上输出调试信息。缺省值是2级。可以由GIT_MERGE_VERBOSITY环境变量覆盖。

merge.<driver>.name

为自定义低级合并驱动程序定义一个人类可读的名称。有关详细信息,请参阅gitattributes [5]。

merge.<driver>.driver

定义实现自定义低级别合并驱动程序的命令。有关详细信息,请参阅gitattributes [5]。

merge.<driver>.recursive

在执行公共祖先之间的内部合并时,命名一个低级合并驱动程序。有关详细信息,请参阅gitattributes [5]。

branch.<name>.mergeOptions

设置合并到分支<name>的默认选项。语法和支持的选项与这些选项相同git merge,但包含空白字符的选项值当前不受支持。