git merge-base a b 返回分支 a 和 b 的最近共同祖先提交的 commit hash,即两者分叉前的最后一个相同提交,仅输出 sha 值,不包含时间、日志或 diff 信息。

git merge-base A B 返回的是什么
它只返回一个 commit hash,比如 abc1234,这个提交是分支 A 和 B 的最近共同祖先(即“分叉起点”)。不是时间戳、不是日志、不是 diff 结果——只是一个 SHA-1 或 SHA-256 值。
这个 commit 就是 Git 认为“两个分支还是一体”的最后一个节点。后续所有提交都属于各自独立演进的历史。
- 如果 A 和 B 从未合并过,
git merge-base A B仍能工作,只要它们有共同祖先(比如都从main拉出) - 如果两个分支完全无关(
--allow-unrelated-histories场景),该命令默认失败,退出码非 0 -
git merge-base --all A B可能输出多个 hash,说明存在多个等价的共同祖先;但日常使用中你只需要第一个(最优的那个)
怎么把 merge-base 的结果转成时间点
它本身不带时间,必须组合其他命令。最常用且可靠的方式是:
git show -s --format="%ci" $(git merge-base main feature)
这会输出类似 2026-05-12 14:23:01 +0800 的 ISO 时间戳。
-
%ci是 committer time,比%ai(author time)更稳定,尤其在 rebase 后不会因作者时间被重写而错乱 - 别用
git log -1 --format=...替代git show -s:前者可能因分页或别名配置意外中断脚本 - 如果
git merge-base返回空(比如分支名拼错、不存在),git show会报错fatal: bad object—— 所以脚本里务必先检查输出是否为空
git merge-base --fork-point 的真实用途和陷阱
它不是用来找“分叉时间”的,而是为 git rebase 服务的辅助逻辑:尝试从 reflog 推测你当初是从哪个旧提交开始基于 upstream 工作的。
- 依赖 reflog,默认保留 90 天;一旦
git reflog expire清理过,--fork-point就失效,可能返回错误 commit - 它返回的结果不稳定:同一对分支,今天跑和明天跑可能不同,因为 reflog 是动态的
- 自动化脚本里应避免直接用
git merge-base --fork-point upstream branch做判断依据;真正可靠的分叉点永远是git merge-base upstream branch - 如果你看到别人用它查“最早时间”,大概率是误用——它甚至不保证返回的 commit 在
upstream历史上存在
脚本调用 merge-base 时最容易崩的三个地方
不是命令本身难,而是周边环境和错误处理没兜住。
- 分支名传错或不存在时,
git merge-base a b退出码非 0,但$(...)会静默吞掉错误,后续命令拿到空字符串,变成git diff ..b这种非法语法 - 没加
--分隔符,当分支名含破折号(如feat/fix-bug)时,Git 可能误判为选项,导致解析失败 - 在 CI 环境中,reflog 常被禁用或截断,
--fork-point失效后 fallback 逻辑缺失,整个定位链断裂
真正关键的不是“怎么运行命令”,而是“怎么让它在出错时不静默失败”。每次用 git merge-base,都该配一句 || exit 1 或显式判断输出长度。











