设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
补丁
调试
电子邮件
外部系统
服务器管理员
指南
管理
管道命令
- 2.43.1 → 2.47.0 无更改
- 2.43.0 11/20/23
- 2.39.1 → 2.42.3 无更改
- 2.39.0 12/12/22
- 2.24.1 → 2.38.5 无更改
- 2.24.0 11/04/19
- 2.23.1 → 2.23.4 无更改
- 2.23.0 08/16/19
- 2.19.3 → 2.22.5 无更改
- 2.19.2 11/21/18
- 2.16.6 → 2.19.1 无更改
- 2.15.4 12/06/19
- 2.11.4 → 2.14.6 无更改
- 2.10.5 09/22/17
- 2.1.4 → 2.9.5 无更改
- 2.0.5 12/17/14
概要
git merge-base [-a | --all] <commit> <commit>… git merge-base [-a | --all] --octopus <commit>… git merge-base --is-ancestor <commit> <commit> git merge-base --independent <commit>… git merge-base --fork-point <ref> [<commit>]
描述
git merge-base 查找两个提交之间的最佳公共祖先,用于三路合并。如果一个公共祖先是另一个公共祖先的祖先,那么它就比另一个公共祖先更好。没有更优的公共祖先的公共祖先是最佳公共祖先,即合并基。请注意,一对提交可能有多个合并基。
操作模式
在最常见的特殊情况下,仅在命令行上指定两个提交表示计算给定的两个提交之间的合并基。
更一般地,在要计算合并基的两个提交中,一个由命令行上的第一个提交参数指定;另一个提交是一个(可能是假设的)提交,它是对命令行上所有剩余提交的合并。
因此,如果指定了两个以上的提交,合并基不一定包含在每个提交参数中。这与 git-show-branch[1] 使用 --merge-base
选项时不同。
- --octopus
-
计算所有提供提交的最佳公共祖先,以准备进行 n 路合并。这模仿了git show-branch --merge-base 的行为。
- --independent
-
不要打印合并基,而是打印提供提交的最小子集,这些子集具有相同的祖先。换句话说,在给定的提交中,列出那些不能从任何其他提交到达的提交。这模仿了git show-branch --independent 的行为。
- --is-ancestor
-
检查第一个 <提交> 是否是第二个 <提交> 的祖先,如果为真,则退出状态为 0,否则退出状态为 1。错误由非零状态(不是 1)表示。
- --fork-point
-
找到分支(或通向 <提交> 的任何历史记录)从另一个分支(或任何引用)<引用> 分叉的位置。这不仅会寻找两个提交的公共祖先,还会考虑 <引用> 的 reflog,以查看通向 <提交> 的历史记录是否从分支 <引用> 的早期版本分叉(见下文对此模式的讨论)。
讨论
给定两个提交 A 和 B,git merge-base A B
将输出一个提交,该提交可通过父关系从 A 和 B 访问。
例如,使用此拓扑结构
o---o---o---B / ---o---1---o---o---o---A
A 和 B 之间的合并基是 1。
给定三个提交 A、B 和 C,git merge-base A B C
将计算 A 与假设提交 M 之间的合并基,该提交是 B 和 C 的合并。例如,使用此拓扑结构
o---o---o---o---C / / o---o---o---B / / ---2---1---o---o---o---A
git merge-base A B C
的结果是 1。这是因为使用 B 和 C 之间的合并提交 M 的等效拓扑结构是
o---o---o---o---o / \ / o---o---o---o---M / / ---2---1---o---o---o---A
git merge-base A M
的结果是 1。提交 2 也是 A 和 M 之间的公共祖先,但 1 是一个更好的公共祖先,因为 2 是 1 的祖先。因此,2 不是合并基。
git merge-base --octopus A B C
的结果是 2,因为 2 是所有提交的最佳公共祖先。
当历史记录涉及交叉合并时,两个提交可能存在多个最佳公共祖先。例如,使用此拓扑结构
---1---o---A \ / X / \ ---2---o---o---B
1 和 2 都是 A 和 B 的合并基。它们之间没有优劣之分(都是最佳合并基)。当未给出 --all
选项时,输出哪个最佳结果是不确定的。
检查两个提交 A 和 B 之间“快进性”的常用习惯用法是(或者至少过去是这样)计算 A 和 B 之间的合并基,并检查它是否与 A 相同,在这种情况下,A 是 B 的祖先。你将在较旧的脚本中经常看到这种习惯用法。
A=$(git rev-parse --verify A) if test "$A" = "$(git merge-base A B)" then ... A is an ancestor of B ... fi
在现代 Git 中,你可以更直接地说
if git merge-base --is-ancestor A B then ... A is an ancestor of B ... fi
代替。
关于分叉点模式的讨论
在使用 git switch -c topic origin/master
创建 topic
分支后,远程跟踪分支 origin/master
的历史记录可能已被回退并重建,导致形成这种历史记录
o---B2 / ---o---o---B1--o---o---o---B (origin/master) \ B0 \ D0---D1---D (topic)
其中 origin/master
曾经指向提交 B0、B1、B2,现在指向 B,你的 topic
分支是在它之上开始的,当时 origin/master
在 B0,并且你在它之上构建了三个提交,D0、D1 和 D。假设你现在想将你在主题上所做的工作重新基到更新后的 origin/master 上。
在这种情况下,git merge-base origin/master topic
将返回上图中 B0 的父级,但 B0^..D 不是 你想在 B 之上重播的提交范围(它包含 B0,这不是你编写的;这是对方在将顶端从 B0 移到 B1 时丢弃的提交)。
git merge-base --fork-point origin/master topic
旨在在这种情况下提供帮助。它不仅考虑 B,还考虑 B0、B1 和 B2(即你的存储库 reflog 知道关于远程跟踪分支的旧顶端),以查看你的主题分支是在哪个提交上构建的,并找到 B0,使你只重播主题上的提交,不包括对方后来丢弃的提交。
因此
$ fork_point=$(git merge-base --fork-point origin/master topic)
将找到 B0,并且
$ git rebase --onto origin/master $fork_point topic
将 D0、D1 和 D 重播到 B 之上,以创建一个新的历史记录,其形状为
o---B2 / ---o---o---B1--o---o---o---B (origin/master) \ \ B0 D0'--D1'--D' (topic - updated) \ D0---D1---D (topic - old)
需要注意的是,你的存储库中的较旧 reflog 条目可能会被 git gc
过期。如果 B0 不再出现在远程跟踪分支 origin/master
的 reflog 中,则 --fork-point
模式显然无法找到它,并会失败,以避免给出随机且无用的结果(例如 B0 的父级,就像没有 --fork-point
选项的相同命令所给出的结果)。
此外,你使用 --fork-point
模式使用的远程跟踪分支必须是你的主题从其顶端分叉的分支。如果你从比顶端更旧的提交分叉,此模式将无法找到分叉点(假设在上例中 B0 不存在,origin/master 从 B1 开始,移动到 B2 然后到 B,并且你在 origin/master^ 上分叉了主题,当时 origin/master 在 B1;历史记录的形状与上面相同,没有 B0,B1 的父级是 git merge-base origin/master topic
正确找到的,但 --fork-point
模式不会,因为它不是曾经位于 origin/master 顶端的提交之一)。
GIT
git[1] 套件的一部分