本地master分支较origin/master超前过多提交的原因排查
问题背景
我负责的项目中,刚提交的合并请求已被合并至GitLab远程仓库(origin)的master分支。之后我提交了一个拼写错误修复的commit,并手动将我的开发分支合并到本地master分支。
运行git status时得到如下输出:
On branch master Your branch is ahead of 'origin/master' by 15 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean
但我认为本地master仅超前3个提交。以下是git log -n5的修改后输出:
commit cdbbbfdaf55deef575914f2cbf8cfec549479973 (HEAD -> master) Merge: bc1a6b9 a32002a Author: Developer 1 (me) Date: Wed Jan 4 11:03:45 2023 +0100 Merge into master commit a32002a75a559943968d8694287dc16b1297e1cf (development-branch) Author: Developer 1 (me) Date: Wed Jan 4 11:02:36 2023 +0100 Fixed typo commit bc1a6b9ba9b56063044730fb20cc5f1b43194dea (origin/master, origin/HEAD) Merge: 91f3302 eabfd24 Author: Developer 2 Date: Wed Jan 4 09:33:41 2023 +0000 Merge branch 'development-branch' into 'master' Development branch See merge request Repository!7 commit eabfd244f4791b66cf4c26a9fb574c9317279021 Author: Developer 1 (me) Date: Wed Jan 4 09:33:41 2023 +0000 Development branch commit 9eb2390feec6650a446bff4e9309bd29c7ed18e8 (origin/development-branch) Merge: 2517a68 91f3302 Author: Developer 1 (me) Date: Wed Jan 4 10:26:37 2023 +0100 Merge
执行git pull显示所有内容都是最新的,这让我困惑。
补充信息
执行git log origin/master..master后,输出显示有15个提交,前三个如下:
commit cdbbbfdaf55deef575914f2cbf8cfec549479973 (HEAD -> master) Merge: bc1a6b9 a32002a Author: Developer 1 (me) Date: Wed Jan 4 11:03:45 2023 +0100 Merge into master commit a32002a75a559943968d8694287dc16b1297e1cf (development-branch) Author: Developer 1 (me) Date: Wed Jan 4 11:02:36 2023 +0100 Fixed typo commit 9eb2390feec6650a446bff4e9309bd29c7ed18e8 (origin/development-branch) Merge: 2517a68 91f3302 Author: Developer 1 (me) Date: Wed Jan 4 10:26:37 2023 +0100 Merge (12 additional commits not shown)
这些是git log -n5中的第1、2、5个提交,但合并提交bc1a6b9并未出现在此列表中,明明git log -n5显示origin/master指向该提交,为何会有这种差异?
原因分析
1. Git计算"超前提交数"的逻辑
Git判断本地分支超前远程分支的提交数时,会统计所有存在于本地分支但不存在于远程分支的提交,包括合并提交引入的历史提交,而不仅仅是你最近新增的提交。
2. 分支历史差异
从日志能看出:
- 远程
origin/master停在合并提交bc1a6b9,这是你的MR被合并后的远程状态。 - 你的本地
development-branch包含了提交9eb2390(一个合并提交),这个提交本身引入了12个未被合并到origin/master的历史提交——这些提交是你在之前开发过程中生成的,但并未通过MR合并到远程master。 - 当你手动把本地
development-branch合并到本地master时,这些隐藏在9eb2390里的12个历史提交也被加入到了本地master的历史中,加上你新增的Fixed typo提交和合并到master的提交,总共15个提交,这就是git status显示超前15个的原因。
3. 为什么git log -n5看不到这些历史提交
git log -n5默认只显示当前分支的最近5个顶层提交,那些被9eb2390合并的历史提交属于分支的深层历史,不会出现在最近5个结果里。而git log origin/master..master会遍历所有本地有但远程没有的提交,包括这些深层历史,所以能显示完整的15个提交。
解决方案
如果你希望本地master的历史和远程master保持一致,只推送你新增的拼写修复提交,可以用变基(rebase)替代合并:
- 切换到你的开发分支:
git checkout development-branch - 拉取远程开发分支的最新内容:
git pull origin development-branch - 将开发分支的提交变基到远程master的最新状态:
git rebase origin/master - 切换回本地master分支:
git checkout master - 将变基后的开发分支内容变基到本地master:
git rebase development-branch
完成后,本地master的历史会变成origin/master + 你的拼写修复提交,此时git status会显示仅超前1个提交,直接推送即可。
内容的提问来源于stack exchange,提问作者glaux

