Setup and Config
Getting and Creating Projects
Basic Snapshotting
Branching and Merging
Sharing and Updating Projects
Inspection and Comparison
Patching
Debugging
External Systems
Server Admin
Guides
- gitattributes
- Command-line interface conventions
- Everyday Git
- Frequently Asked Questions (FAQ)
- Glossary
- Hooks
- gitignore
- gitmodules
- Revisions
- Submodules
- Tutorial
- Workflows
- All guides...
Administration
Plumbing Commands
- 2.43.0 11/20/23
- 2.42.1 no changes
- 2.42.0 08/21/23
- 2.40.0 → 2.41.0 no changes
- 2.39.3 04/17/23
- 2.38.1 → 2.39.2 no changes
- 2.38.0 10/02/22
- 2.35.1 → 2.37.7 no changes
- 2.35.0 01/24/22
- 2.34.1 → 2.34.8 no changes
- 2.34.0 11/15/21
- 2.33.2 → 2.33.8 no changes
- 2.33.1 10/12/21
- 2.33.0 08/16/21
- 2.30.1 → 2.32.7 no changes
- 2.30.0 12/27/20
- 2.29.1 → 2.29.3 no changes
- 2.29.0 10/19/20
- 2.27.1 → 2.28.1 no changes
- 2.27.0 06/01/20
概述
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 来执行合并,并在创建合并提交前停止,以便让用户有机会在提交前检查和进一步调整合并结果。
请注意,快进更新并不产生合并提交,因此没有办法用 --no-commit 停止这些合并。 因此,如果你想确保你的分支不被合并命令改变或更新,请一起使用 --no-ff 和 --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
-
指定当被合并的历史已经是当前历史的后代时,如何处理合并的问题。 默认为`--ff`,除非合并的是一个有注释的(可能是有签名的)标签,在这种情况下,`--no-ff`假设这个标签并没有存储在`refs/tags/`层次结构中的自然位置。
如果使用
--ff
,可能的话,以快进方式解决合并问题(只更新分支指针以匹配合并后的分支;不创建合并提交)。 当不可能时(当合并的历史不是当前历史的后代),创建一个合并提交。使用`--no-ff`,在所有情况下都创建一个合并提交,即使该合并可以作为一个快进解决。
使用`--ff-only`,在可能的情况下,以快进的方式解决合并的问题。 当不可能时,拒绝合并并以非零状态退出。
- -S[<keyid>]
- --gpg-sign[=<keyid>]
- --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
-
在提交日志信息的末尾添加提交者的 "Signed-off-by "预告片。 签名的意义取决于你所提交的项目。 例如,它可以证明提交者有权利在项目许可下提交作品,或者同意一些贡献者的陈述,如开发者的原产地证书。 关于Linux内核和Git项目使用的证书,请参见http://developercertificate.org)。 请查阅你要贡献的项目的文档或领导层,以了解该项目如何使用签名。
--no-signoff选项可以用来反驳先前在命令行上的-signoff选项。
- --stat
- -n
- --no-stat
-
在合并结束时显示一个差异状态。差异状态也由配置选项merge.stat控制。
使用-n或—no-stat,在合并结束时不显示差异状态。
- --squash
- --no-squash
-
产生工作区和索引状态,就像发生了真正的合并一样(除了合并信息),但不实际提交,不移动`HEAD`,也不记录`$GIT_DIR/Merge_HEAD`(以导致下一个`git commit`命令创建一个合并提交)。 这允许你在当前分支的基础上创建一个单一的提交,其效果与合并另一个分支相同(如果是多路分支,则更多)。
使用 --no-squash 进行合并并提交结果。这个选项可以用来覆盖 --quash 选项。
使用 --squash,--commit 是不允许的,而且会失败。
- --[no-]verify
-
默认情况下,会运行 pre-merge 和 commit-msg 事件hook。 当给定 `--no-verify`时,这些将不会执行。 参见 githooks[5]。
- -s <strategy>
- --strategy=<strategy>
-
使用给定的合并策略;可以多次提供,以指定它们应该被尝试的顺序。 如果没有`-s`选项,则使用一个内置的策略列表(当合并单个头时使用`ort`,否则使用`octopus`)。
- -X <选项>
- --strategy-option=<option>
-
将合并策略的特定选项传递给合并策略。
- --verify-signatures
- --no-verify-signatures
-
验证被合并的侧边分支的提示提交是否用有效的密钥签署,即一个具有有效uid的密钥:在默认的信任模型中,这意味着签署密钥是由一个受信任的密钥签署。 如果侧边分支的提示提交没有用有效的密钥签名,则合并被终止。
- --summary
- --no-summary
-
与 --stat 和 --no-stat 同义;这些都弃用了,将来会被删除。
- -q
- --quiet
-
安静地操作。暗指 --no-progress。
- -v
- --verbose
-
详细日志。
- --progress
- --no-progress
-
明确地打开/关闭进度。如果两者都没有指定,如果标准错误连接到终端,就会显示进度。 注意,并非所有的合并策略都支持进度报告。
- --autostash
- --no-autostash
-
Automatically create a temporary stash entry before the operation begins, record it in the special 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. -
默认情况下,`git merge`命令拒绝合并那些没有共同祖先的历史。 当合并两个独立开始的项目的历史时,这个选项可以用来覆盖这个安全性。由于这是一个非常罕见的情况,没有配置变量来默认启用,也不会被添加。
- -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-auto-oupdate`是一个很好的方法,在用单独的 `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 unlessMERGE_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`、索引和工作区将更新到这个版本。 在工作区中可以有一些修改,只要它们不重叠;更新将保留这些修改。
当不清楚如何调和这些变化时,就会发生以下情况:
-
`HEAD`的指针保持不变。
-
`MERGE_HEAD`参数被设置为指向另一个分支头部。
-
合并干净的路径在索引文件和你的工作区中都更新了。
-
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 fromMERGE_HEAD
(you can inspect the stages withgit ls-files -u
). The working tree files contain the result of the merge operation; i.e. 3-way merge results with familiar conflict markers<<<
===
>>>
. -
会写入一个特殊的
AUTO_MERGE
引用,指向一个与当前工作区内容(包括文本冲突的冲突标记)相对应的目录树。 请注意,只有在使用 ort 合并策略(默认)时,才会写入这个引用。 -
没有其他变化。 特别是,你在开始合并之前的本地修改将保持不变,它们的索引条目保持原样,即匹配`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 theHEAD
andMERGE_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
属于 git[1] 文档