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 pull
并git merge
会停止,而不做任何事情时,本地提交的更改与文件重叠git pull
/ git merge
可能需要更新。
为了避免在合并提交中记录不相关的更改,git pull
并且git merge
如果在索引中相对于HEAD
提交注册了任何更改,也会中止。(一个例外是当已更改的索引条目处于已经合并的状态时。)
如果所有已命名的提交都已经是祖先HEAD
,git merge
则会提前退出,并显示“已更新”消息。
Fast-forward merge
通常当前分支头是命名提交的祖先。这是最常见的情况,特别是在从git pull
以下情况调用时:您正在跟踪上游存储库,您没有提交本地更改,现在您想更新为更新的上游修订版。在这种情况下,不需要新的提交来存储组合的历史; 相反,HEAD
(与索引一起)更新为指向指定的提交,而不创建额外的合并提交。
该行为可以通过该--no-ff
选项进行抑制。
真正的合并
除了在快进合并中(见上文),要合并的分支必须通过合并提交绑定在一起,合并提交将它们都作为其父项。
提交一个合并版本来协调所有要合并的分支的更改,并将您的HEAD
索引和工作树更新为它。只要不重叠,可以在工作树中进行修改; 更新将保留它们。
如果不清楚如何协调更改,则会发生以下情况:
- 该
HEAD
指针保持不变。 - 该
MERGE_HEAD
ref被设置为指向另一个分支头。 - 干净合并的路径在索引文件和工作树中都会更新。
- 对于冲突的路径,索引文件最多可以记录三个版本:第1阶段存储公共祖先的版本,第2阶段的版本
HEAD
和第3 阶段的版本MERGE_HEAD
(可以检查阶段git ls-files -u
)。工作树文件包含“合并”程序的结果; 即3路合并结果与熟悉的冲突标记<<<
===
>>>
。 - 没有其他更改。特别是,在开始合并之前进行的本地修改将保持不变,并且它们的索引条目保持原样,即匹配
HEAD
。
如果您尝试导致复杂冲突并想重新开始的合并,则可以使用恢复git merge --abort
。
Merging tag
合并注释(也可能是签名)标记时,即使可以进行快进合并,Git也会始终创建合并提交,并且提交消息模板是使用标记消息准备的。另外,如果标签已签名,则签名检查会作为消息模板中的注释报告。另请参阅git-tag [1]。
当您只想将导致正好被标记的提交的工作集成时,例如与上游发行版同步时,您可能不想进行不必要的合并提交。
在这种情况下,您可以在喂食之前自己“unwrap”标签git merge
,或者--ff-only
在您自己没有任何工作时通过。例如
git fetch origin git merge v1.2.3^0git 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 commit
或git merge --continue
密封交易。后一个命令在调用之前检查是否存在正在进行的(中断的)合并git commit
。
您可以通过许多工具解决冲突:
- 使用mergetool。
git mergetool
启动一个图形化的合并工具,这将通过合并工作。 - 看看差异。
git diff
将显示三方差异,突出显示来自版本HEAD
和MERGE_HEAD
版本的更改。 - 看看每个分支的差异。
git log --merge -p <path>
将首先显示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我们的过时的- 将分支合并
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 merge
和git 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 buttheir
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
,但包含空白字符的选项值当前不受支持。