Git:merge 命令

Oct 21, 2021

目录


ref: https://git-scm.com/docs/git-merge


命令


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

git-merge - Join two or more development histories together


描述


将现有的提交(named commits,从这个提交起,他们的提交记录开始产生分歧) 合并到当前分支. git pull命令使用这个命令来将另外一个仓库的修改合并到当前分支,也可以使用此命令手动将两个分支合并.

假定存在一下历史记录,并且当前分支是 master:

1      A---B---C topic
2     /
3    D---E---F---G master

git merge topic 将会将 topic 分支的修改应用到分支 master 上, 因为从提交 E 开始两个分支开始产生分歧。它的结果将是: 产生一个新的 commit H,它有两个父commit,分别是 C 和 G. 还有一个用户指定的日志消息。

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

第二种语法 git merge --abort 只可以在合并操作导致了冲突(conflicts)之后使用。 git merge --abort 命令将会尝试中止合并操作,然后尝试恢复到合并操作之前的状态。 然后,如果在执行合并操作之前,存在没有提交的修改(特别是在合并开始后,如果这些更改被进一步修改),git merge --abort 命令在某些情况下是无法回复到合并操作之前的操作的。 因此:

警告: 不建议在存在未提交修改的状态下使用 git merge

第三种语法 git merge --continue 只可以在合并操作导致了冲突(conflicts)之后使用。


选项


TODO:


PRE-MERGE 检查


在准备合并外部修改之前,你应该使得你的修改处于良好的状态,并将它提交到本地,这样子这些修改在合并操作导致冲突之后不受影响。 参考 git-stash. 当本地未提交的更改与 git pull/ git merge 可能需要更新的文件重叠时,git pullgit merge 将不做任何操作而直接停止.

为了避免在 merge commit 中记录不相关的修改, git pullgit merge 将会中止,如果索引(index)中有相对于 HEAD commit 的任何更改。

如果所有的提交已经是 HEAD 的祖先(ancestors),那么 git merge 将会提交结束,并返回消息 ‘Already up to date’


FAST-FORWARD MERGE


通常当前分支的 HEAD 将会是将要合并提交的祖先(ancestor)。 这是最常见的情况,尤其是在使用 git pull 的情况下: 你的本地仓库跟踪一个远程仓库, 你本地没有任何提交,然后你想将远程新的修改更新到本地仓库。 在这种情况下,不需要创建一个新的提交来保存合并操作的历史记录。 取而代之,只需要更新 HEAD , 让 HEAD 指向你希望更新到的提交, 这个过程中不要额外的合并提交。

你可以通过使用 --no-ff 选项来禁止这种行为。


TRUE MERGE


在 FAST-FORWARD 合并之外,TRUE MERGE 通过一个合并提交(merge commit)将多个分支联系到一起,新创建的合并提交作为被合并分支的子.

一个合并之后的版本将会被提交,这个合并的版本协调所有要合并的分支的修改,HEAD,索引(index), 和工作目录(working tree) 都会被更新,指向新的合并之后的版本。 如果你的工作目录中有未提交的修改也可以执行合并操作,前提是这些修改没有重合。

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

  1. HEAD 保持不变
  2. MERGE_HEAD 引用指向另一个分支
  3. 可以清楚地合并的路径将被更新, 索引和工作目录都会更新
  4. 对于冲突的路径, 索引文件中记录了三个版本: stage 1 版本保存他们共同的父版本, stage 2 版本来自 HEAD, stage 3 版本来自 MERGE_HEAD (可以通过命令 git ls-files -u 来查看这些 stage), 工作目录下的文件包含合并的结果。
  5. 没有做其他更改。 特别是,在开始合并之前就存在的本地修改将保持不变,它们的索引条目也不变,和 HEAD 匹配。

如果你的某个合并操作导致了复杂的冲突形况, 你想重新开始,可以通过命令 git merge --abort 进行恢复。


合并 tag


当合并一个 annotated tag (可能还有签名)的时候,git 总是会创建一个合并提交,即使可以进行 fast-forward 合并,也会创建合并提交。 此外,如果 tag 被签名,签名检查将作为消息模板中的注释报告。 参考 git-tag


如何标记冲突


在合并操作中,工作目录中的文件将会被更新以反应合并操作的结果。 在对于共同父版本的修改中,对于那些没有重叠的修改,会被直接作为最终结果。 当合并的双方都对同一区域做了修改, git 不知道如何合并, git 会将双方的修改都保留下来,让你决定如何合并两者。

合并结果看起来是这样的:

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

使用 <<<<<<<, =======, >>>>>>> 来标识 git 无法自动合并的修改。 ======= 之前的部分是你的修改,======= 之后的部分是另一方的修改。

对于上述例子中,

1yours:sample.txt
2Conflict resolution is hard;
3let's go shopping.

是你的修改。

1Git makes conflict resolution easy.

是另一方的修改。

默认的格式无法显示出冲突之处原先的内容。

你可以修改 merge.conflictStyle 配置项的值为 diff3. 在这种格式下,上述冲突看起来是这样的:

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

除了原先的 >>>>>>>, =======>>>>>>>, 它使用了另外一个标记 |||||||. 跟在这个标记之后的内容便是原始的内容。

原始内容是:

1Conflict resolution is hard.

如何解决冲突


在发生冲突之后,你可以做这两件事:

  • 不合并。 将索引文件(index file) 重置到 HEAD, 将工作目录文件重置. 这里可以使用 git merge --abort
  • 解决冲突。 Git 会在工作目录中标记冲突。 手动编辑冲突文件,然后使用 git add 将文件添加到索引(index)。 使用 git commitgit merge --continue 来完成合并。

你可以使用以下工具来解决冲突:

  • 使用合并工具。 git mergetool 启动一个带有图形界面的合并工具,你可以使用该工具来合并冲突
  • 查看不同(diff)。 git diff 用于显示不同,高亮来自 HEADMERGE_HEAD 的版本
  • 查看每个分支的不同。 git log --merge -p <path>
  • 查看原始的内容。 git show :1:filename 查看冲突的分支的共同父版本, git show :2:filename 查看 HEAD 版本, git show :3:filename 查看 MERGE_HEAD 版本。

例子


  • 在当前分支的基础上,合并分支 fixesenhancements
1git merge fixes enhancements
  • 使用 ours 合并策略,将分支 obsolete 分支合并到当前分支
1git merge -s ours obsolete
  • 将分支 maint 合并到当前分支,但是不要自动创建新的提交
1git merge --no-commit maint

合并策略


可以使用 -s 选项来指定合并策略。 一些合并策略有自己特有的选线,通过 -X<option> 来指定。

  • recursive
    • ours
    • theirs
    • patience
    • diff-algorithm=[patience|minimal|histogram|myers]
    • ignore-space-change
    • ignore-all-space
    • ignore-space-at-eol
    • ignore-cr-at-eol
    • renormalize
    • no-renormalize
    • no-renames
    • find-renames[=]
    • rename-threshold=
    • subtree[=]
  • ort
  • resolve
  • octopus
  • ours
  • subtree

TODO:

END!!!


Tags