Git
简体中文 ▾ Topics ▾ Latest version ▾ git-merge last updated in 2.44.0

名称

git-merge - Join two or more development histories together

概述

git merge [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
	[--no-verify] [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
	[--[no-]allow-unrelated-histories]
	[--[no-]rerere-autoupdate] [-m <msg>] [-F <file>]
	[--into-name <branch>] [<commit>…​]
git merge (--continue | --abort | --quit)

描述

将指定的提交内容(从它们的历史与当前分支相分离时起)并入当前分支。 这条命令被 "git pull "用来合并另一个仓库的改动,也可以用手将一个分支的改动合并到另一个分支。

假设存在以下历史,且当前分支为"master":

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

然后"git merge topic"将重现`topic`分支从`master`(即`E`)分流到`master`之上的当前提交(C)所做的修改,并将结果与两个父提交的名称和用户描述修改的日志信息一起记录在一个新提交中。在操作之前,ORIG_HEAD`被设置为当前分支(`C)的顶端。

	  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 来执行合并,并在创建合并提交前停止,以便让用户有机会在提交前检查和进一步调整合并结果。

Note that fast-forward updates do not create a merge commit and therefore there is no way to stop those merges with --no-commit. Thus, if you want to ensure your branch is not changed or updated by the merge command, use --no-ff with --no-commit.

--edit
-e
--no-edit

在提交成功的机械合并之前,调用一个编辑器来进一步编辑自动生成的合并信息,以便用户可以解释和证明合并的合理性。可以使用`--no-edit`选项来接受自动生成的信息(但是不鼓励亲这么做)。 如果你在命令行中用`-m`选项给出一个草稿信息,并想在编辑器中编辑它,--edit(或`-e`)选项仍然有用。

旧的脚本可能依赖于不允许用户编辑合并日志信息的历史行为。他们会在运行`git merge`时看到一个编辑器被打开。为了使这些脚本更容易调整到最新的行为,可以在脚本的开头将环境变量`GIT_MERGE_AUTOEDIT`设置为`no`。

--cleanup=<模式>

这个选项决定了在提交前如何清理合并信息。更多细节见git-commit[1]。此外,如果`<模式>的值为 `scissors,在发生合并冲突时,scissors将被附加到 "MERGE_MSG "上,然后传递给提交机制。

--ff
--no-ff
--ff-only

Specifies how a merge is handled when the merged-in history is already a descendant of the current history. --ff is the default unless merging an annotated (and possibly signed) tag that is not stored in its natural place in the refs/tags/ hierarchy, in which case --no-ff is assumed.

With --ff, when possible resolve the merge as a fast-forward (only update the branch pointer to match the merged branch; do not create a merge commit). When not possible (when the merged-in history is not a descendant of the current history), create a merge commit.

使用`--no-ff`,在所有情况下都创建一个合并提交,即使该合并可以作为一个快进解决。

With --ff-only, resolve the merge as a fast-forward when possible. When not possible, refuse to merge and exit with a non-zero status.

-S[<keyid>]
--gpg-sign[=<键 ID>]
--no-gpg-sign

对合并后的提交进行 GPG 签名。keyid 参数是可选的,默认为提交者的身份;如果指定,它必须与选项连在一起,不能有空格。--no-gpg-sign 对于反命令 commit.gpgSign 配置变量和早期的 --gpg-sign 都很有用。

--log[=<n>]
--no-log

除了分支名称外,在日志信息中最多只用<n>个正在合并的实际提交的单行描述来填充。参见 git-fmt-merge-msg[1]

如果使用 --no-log,则不列出被合并的实际提交内容的单行描述。

--signoff
--no-signoff

Add a Signed-off-by trailer by the committer at the end of the commit log message. The meaning of a signoff depends on the project to which you’re committing. For example, it may certify that the committer has the rights to submit the work under the project’s license or agrees to some contributor representation, such as a Developer Certificate of Origin. (See https://developercertificate.org for the one used by the Linux kernel and Git projects.) Consult the documentation or leadership of the project to which you’re contributing to understand how the signoffs are used in that project.

--no-signoff选项可以用来反驳先前在命令行上的—​signoff选项。

--stat
-n
--no-stat

在合并结束时显示一个差异状态。差异状态也由配置选项merge.stat控制。

使用-n或—​no-stat,在合并结束时不显示差异状态。

--squash
--no-squash

Produce the working tree and index state as if a real merge happened (except for the merge information), but do not actually make a commit, move the HEAD, or record $GIT_DIR/MERGE_HEAD (to cause the next git commit command to create a merge commit). This allows you to create a single commit on top of the current branch whose effect is the same as merging another branch (or more in case of an octopus).

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

使用 --squash,--commit 是不允许的,而且会失败。

--[no-]verify

By default, the pre-merge and commit-msg hooks are run. When --no-verify is given, these are bypassed. See also githooks[5].

-s <策略>
--strategy=<策略>

Use the given merge strategy; can be supplied more than once to specify them in the order they should be tried. If there is no -s option, a built-in list of strategies is used instead (ort when merging a single head, octopus otherwise).

-X <选项>
--strategy-option=<选项>

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

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

Verify that the tip commit of the side branch being merged is signed with a valid key, i.e. a key that has a valid uid: in the default trust model, this means the signing key has been signed by a trusted key. If the tip commit of the side branch is not signed with a valid key, the merge is aborted.

--summary
--no-summary

与 --stat 和 --no-stat 同义;这些都弃用了,将来会被删除。

-q
--quiet

安静地操作。暗指 --no-progress。

-v
--verbose

详细日志。

--progress
--no-progress

Turn progress on/off explicitly. If neither is specified, progress is shown if standard error is connected to a terminal. Note that not all merge strategies may support progress reporting.

--autostash
--no-autostash

Automatically create a temporary stash entry before the operation begins, record it in the ref MERGE_AUTOSTASH and apply it after the operation ends. This means that you can run the operation on a dirty worktree. However, use with care: the final stash application after a successful merge might result in non-trivial conflicts.

--allow-unrelated-histories

By default, git merge command refuses to merge histories that do not share a common ancestor. This option can be used to override this safety when merging histories of two projects that started their lives independently. As that is a very rare occasion, no configuration variable to enable this by default exists and will not be added.

-m <消息>

设置用于合并提交的提交信息(如果创建了一个的话)。

如果指定了`--log`,正在合并的提交的简短日志将被附加到指定的消息中。

The git fmt-merge-msg command can be used to give a good default for automated git merge invocations. The automated message can include the branch description.

--into-name <branch>

准备默认的合并信息,就像合并到分支`<分支>`一样,而不是真正要合并的分支名称。

-F <文件>
--file=<文件>

读取用于合并提交的提交信息(如果创建了)。

如果指定了`--log`,正在合并的提交的简短日志将被附加到指定的消息中。

--rerere-autoupdate
--no-rerere-autoupdate

在 rerere 机制重用当前冲突的记录解析来更新工作树中的文件后,允许它也用解析的结果来更新索引。 --no-rerere-autoupdate`是一个很好的方法,在用单独的 `git add 提交结果到索引之前,可以反复检查 rerere 所做的事情,并抓住潜在的错误合并。

--overwrite-ignore
--no-overwrite-ignore

默认会静默地覆盖合并结果中被忽略的文件。使用`--no-overwrite-ignore`来终止。

--abort

中止当前的冲突解决过程,并尝试重建合并前的状态。工作区会自动应用自动存储条目。

如果合并开始时有未提交的工作区变化,'git merge --abort’在某些情况下将无法重现这些变化。因此,建议在运行’git merge’之前,一定要提交或储存你的修改。

git merge --abort is equivalent to git reset --merge when MERGE_HEAD is present unless MERGE_AUTOSTASH is also present in which case git merge --abort applies the stash entry to the worktree whereas git reset --merge will save the stashed changes in the stash list.

--quit

忘记当前正在进行的合并。让索引和工作区保持原样。如果`MERGE_AUTOSTASH`存在,储藏库条目将被保存到储藏库列表。

--continue

在 "git merge "因冲突而停止后,你可以通过运行 "git merge --continue "来结束当前合并(见下文 "如何解决冲突"部分)。

<commit>…​

提交,通常是其他分支负责人,合并到我们的分支中。 指定多个提交将创建具有两个以上父项的合并(亲切地称为八爪/多路合并)。

如果命令行没有给出提交,则合并当前分支被配置为上游的远程跟踪分支。 参见本手册页的配置部分。

当指定`FETCH_HEAD`(没有其他提交)时,之前调用 git fetch`进行合并时记录在.git/FETCH_HEAD`文件中的分支会被合并到当前分支。

合并前检查

在应用外部的修改之前,你应该把自己的工作做好,并在本地提交,这样在有冲突的时候就不会被打乱了。 参见 git-stash[1]。 "git pul "和 "git merge "会在本地未提交的修改与 "git pull"/"git merge "可能需要更新的文件重叠时会不做任何操作,立即停止。

为了避免在合并提交中记录不相关的变化,'git pull’和’git merge’也会在相对于`HEAD`提交的索引中存在任何变化时中止。 (根据使用的合并策略,这一规则可能存在特殊的狭义例外,但一般来说,索引必须与HEAD相匹配。)

如果所有命名的提交都已经是`HEAD`的祖先,'git merge’将提前退出,提示 "已经是最新的。"

快进式合并

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

这种行为可以通过`--no-ff`选项来抑制。

正确的合并

除了快进合并(见上文),被合并的分支必须由一个以它们两个为父分支的合并提交捆绑在一起。

一个调和了所有要合并的分支的修改的合并版本被提交,你的`HEAD`、索引和工作区将更新到这个版本。 在工作区中可以有一些修改,只要它们不重叠;更新将保留这些修改。

当不清楚如何调和这些变化时,就会发生以下情况:

  1. `HEAD`的指针保持不变。

  2. `MERGE_HEAD`参数被设置为指向另一个分支头部。

  3. 合并干净的路径在索引文件和你的工作区中都更新了。

  4. For conflicting paths, the index file records up to three versions: stage 1 stores the version from the common ancestor, stage 2 from HEAD, and stage 3 from MERGE_HEAD (you can inspect the stages with git ls-files -u). The working tree files contain the result of the merge operation; i.e. 3-way merge results with familiar conflict markers <<< === >>>.

  5. 会写入一个特殊的 AUTO_MERGE 引用,指向一个与当前工作区内容(包括文本冲突的冲突标记)相对应的目录树。 请注意,只有在使用 ort 合并策略(默认)时,才会写入这个引用。

  6. 没有其他变化。 特别是,你在开始合并之前的本地修改将保持不变,它们的索引条目保持原样,即匹配`HEAD`。

如果你尝试的合并导致了复杂的冲突,并想重新开始,你可以用`git merge --abort`恢复。

合并标签

当合并一个有注释的(可能是有签名的)标签时,即使可以进行快速合并,Git也会创建一个合并提交,并且会一起准备提交消息模板和标签消息。 此外,如果标签有签名,签名检查会在消息模板中作为注释报告。参见 git-tag[1]

当你只想与恰好被标记的提交的工作整合时,比如说与上游发布点同步,你可能不想做一个不必要的合并提交。

在这种情况下,你可以在把标签送入`git merge`之前自己 "解包",或者在自己没有任何工作的时候设置`--ff-only`,如下例。

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

HOW CONFLICTS ARE PRESENTED

在合并过程中,工作区文件被更新以反映合并的结果。 在对共同祖先的版本所做的修改中,非重叠的修改(即你改变了文件的某个区域,而另一方则保留了该区域,反之亦然)会被逐字纳入最终结果中。 然而,当双方都对同一区域进行了修改时,Git不能随机地选择一方而不是另一方,而是要求你通过保留双方对该区域的修改来解决这个问题。

默认情况下,Git使用与RCS套件中的 "merge"程序相同的样式来呈现这样一个有冲突的大块,像这样:

这里是与共同的祖先相比没有变化的行。
祖先没有变化,或者因为只有一方发生了变化而得到干净的解决、
或者因为两边都有相同的变化而被干净地解决了。
<<<<<<< yours:sample.txt
冲突的解决是困难的;
让我们去购物吧。
=======
Git让冲突解决变得简单。
>>>>>>> theirs:sample.txt
而这里是另一行干净利落的解决或未修改的内容。

发生一对冲突变化的区域被标记为`<<<<<<<=======>>>>>>>`。 `=======`之前的部分通常是你做的修改,而之后的部分通常是别人的修改。

默认的格式并不显示原文在冲突区说了什么。 你无法知道有多少行被删除,并被替换成你方的芭比娃娃的言论。 你唯一能知道的是,你方想说这很难,你更愿意去购物,而另一方则想说这很容易。

通过将 "merge.conflictStyle "配置变量设置为 "diff3 "或 "zdiff3",可以使用另一种风格。 在 "diff3 "风格中,上述冲突可能看起来像这样:

这里是与共同的祖先相比没有变化的行。
祖先没有变化,或者因为只有一方发生了变化而得到了干净的解决、
<<<<<<< yours:sample.txt
或干净地解决了,因为双方都以同样的方式改变了。
冲突的解决是很难的;
让我们去购物吧。
||||||| base:sample.txt
或干净利落地解决了,因为双方的变化都一样。
冲突的解决是很难的。
=======
或干净利落地解决了,因为双方都有相同的变化。
Git使冲突解决变得容易。
>>>>>>> theirs:sample.txt
而这里是另一行被干净地解决或未修改的。

while in "zdiff3" style, it may look like this:

Here are lines that are either unchanged from the common
ancestor, or cleanly resolved because only one side changed,
or cleanly resolved because both sides changed the same way.
<<<<<<< yours:sample.txt
Conflict resolution is hard;
let's go shopping.
||||||| base:sample.txt
or cleanly resolved because both sides changed identically.
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 commit’或’git merge --continue’解决。后一个命令在调用’git commit’之前会检查是否有一个(中断的)合并正在进行。

你可以用一些工具来解决冲突:

  • Use a mergetool. git mergetool to launch a graphical mergetool which will work through the merge with you.

  • Look at the diffs. git diff will show a three-way diff, highlighting changes from both the HEAD and MERGE_HEAD versions. git diff AUTO_MERGE will show what changes you’ve made so far to resolve textual conflicts.

  • 看看每个分支的差异。`git log --merge -p <路径>`将首先显示`HEAD`版本的差异,然后是`MERGE_HEAD`版本。

  • 看一下原件。 `git show :1:filename`显示共同的祖先,`git show :2:filename`显示`HEAD`版本,`git show :3:filename`显示`MERGE_HEAD`版本。

实例

  • 合并分支 fixes 和 `enhancements`到当前分支之上, 进行多路合并。

    $ git merge fixes enhancements
  • 将分支`obsolete`合并到当前分支,使用`ours`的合并策略:

    $ git merge -s ours obsolete
  • 合并分支`maint`到当前分支,但是我们不做自动创建新提交:

    $ git merge --no-commit maint

    当您想在合并中加入进一步的更改,或者您想手动编写合并提交信息时,就可以使用此功能。

    你应该避免滥用这个选项,它可以在合并提交中偷偷地进行版本库中实质性的修改。 小的修正,例如修改发布日志内容/版本名称,是推荐的。

合并战略

合并机制(git merge`和`git pull`命令)允许用`s`选项来选择后端'合并策略'。 一些策略也可以采取自己的选项,可以通过给`git merge`和/或`git pull`的-X<选项>`参数来传递。

ort

这是拉取或合并一个分支时的默认合并策略。 这个策略只能使用三方合并算法解决两个头。 当有一个以上的共同祖先可用于三方合并时,它会创建一个共同祖先的合并树,并将其作为三方合并的参考树。 据报道,通过对Linux 2.6内核开发历史中的实际合并提交的测试,这导致了较少的合并冲突,而不会引起错误的合并。 此外,这个策略可以检测并处理涉及重命名的合并。 它并不使用检测到的副本。 这个算法的名字是一个缩写("Ostensibly Recursive’s Twin"),来自于它是作为以前的默认算法`recursive`的替代而编写的。

ort 策略可以采取以下选项:

ours

这个选项通过倾向于 "我们" 的版本,迫使冲突的猎物被自动解决。 另一棵目录树上与我们这边不冲突的变化会反映在合并结果中。 对于一个二进制文件,整个内容都来自我们这边。

这不应该与 "我们的" 合并策略相混淆,后者甚至根本不看另一棵目录树包含了什么。 它抛弃了其他树所做的一切,宣布 "我们的" 历史包含了其中所发生的一切。

theirs

这与 "我们的" 相反;注意,与 "我们的" 不同,没有 "他们的" 合并策略来混淆这个合并选项。

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

为了进行三方合并,将具有指定类型的空白变化的行视为没有变化。 但混合了其他改动的行的空白改动不会被忽略。 参见git-diff[1] -b, -w, --ignore-space-at-eol, 和 --ignore-cr-at-eol

  • 如果 "他们的" 版本只在一行中引入了空白的变化,则使用 "我们的" 版本;

  • 如果 "我们的" 版本引入了空白的变化,但 "他们的" 版本包括一个实质性的变化,则使用 "他们的" 版本;

  • 否则,合并将以常规方式进行。

renormalize

在解决三方合并时,这将对一个文件的所有三个阶段运行虚拟检出和检入。 这个选项是为了在合并具有不同清洁过滤器或行末规范化规则的分支时使用。 详情见 gitattributes[5] 中的 "合并具有不同检入/检出属性的分支"。

no-renormalize

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

find-renames[=<n>]

开启重名检测,可选择设置相似度阈值。 这是默认的。这覆盖了 merge.renames 配置变量。 参见git-diff[1] --find-renames

rename-threshold=<n>

废弃的,find-renames=<n> 的同义词。

subtree[=<路径>]

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

recursive

这只能用三方合并算法解决两个头。 当有一个以上的共同祖先可用于三方合并时,它会创建一个共同祖先的合并树,并使用它作为三方合并的参考树。 据报道,通过对Linux 2.6内核开发历史中的实际合并提交的测试,这导致了较少的合并冲突,而不会引起错误的合并。 此外,它可以检测并处理涉及重命名的合并。 它并不使用检测到的副本。 从Git v0.99.9k到v2.33.0,这是解决双头的默认策略。

recursive 策略采用与 ort 相同的选项。 然而,有三个 ort 忽略的额外选项(上面没有记录),对 recursive 策略有潜在的作用:

patience

废弃的,diff-algorithm=patience 的同义词。

diff-algorithm=[patience|minimal|histogram|myers]

在合并时使用不同的差异算法,这可以帮助避免由于不重要的匹配行(比如不同函数的大括号)而发生的错误合并。 参见git-diff[1] --diff-algorithm。 注意,ort 特定 diff-algorithm=histogram,而`recursive`默认为`diff.algorithm`配置设置。

no-renames

关闭重名检测。这覆盖了 merge.renames 的配置变量。 参见git-diff[1] --no-renames

resolve

这只能用三方合并算法解决两个头(即当前分支和你拉来的另一个分支)。 它试图仔细检测纵横交错的合并歧义。 它不处理重名。

octopus

这可以解决有两个以上头的情况,但拒绝做复杂的合并,需要手动解决。 它主要是用于将主题分支头捆绑在一起。 当拉动或合并一个以上的分支时,这是默认的合并策略。

ours

这可以解决任何数量的头,但合并的结果总是当前分支头的树,有效地忽略了所有其他分支的变化。 它是用来取代侧边分支的旧开发历史的。 注意,这与 recursive 合并策略的-Xours选项不同。

subtree

这是一个修正的 ort 策略。当合并树A和B时,如果B对应于A的子树,B首先被调整为与A的树结构相匹配,而不是在同一级别读取树。这种调整也是针对共同祖先树进行的。

对于使用三方合并的策略(包括默认的 ort 策略),如果在两个分支上都做了修改,但后来在其中一个分支上被撤销,那么这个修改就会出现在合并后的结果中;有些人觉得这种行为令人困惑。 出现这种情况是因为在执行合并时只考虑头部和合并基数,而不是单个提交。 因此,合并算法认为被恢复的修改根本就没有变化,而是用被修改的版本来代替。

配置

分支 .<名字>.合并操作选项

设置合并到分支<分支名>的默认选项。语法和支持的选项与’git merge’相同,不过目前不支持包含空格的选项值。

Warning

Missing zh_HANS-CN/includes/cmd-config-section-rest.txt

See original version for this content.

Warning

Missing zh_HANS-CN/config/merge.txt

See original version for this content.

GIT

属于 git[1] 文档

scroll-to-top