看懂 Git 状态:为什么会出现“冲突已解决,但仍在合并中”?
在日常开发里,很多人都见过这样一段 git status 输出:
On branch master
Your branch and 'origin/master' have diverged,
and have 2 and 1 different commits each, respectively.
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: foo/bar/a.js
modified: foo/bar/b.vue
modified: foo/bar/c.vue
Changes not staged for commit:
modified: .env.development
这个状态看起来信息很多,实际上可以拆成一句话:
本地分支和远端分支已经分叉,你发起过一次合并,冲突也处理完了,但还没提交最终的 merge commit;与此同时,工作区里还有额外未暂存的改动。
本文就从这个状态出发,讲清楚它是怎么产生的、为什么会这样、以及应该如何理解。
一、先逐条看懂 git status
1. diverged:本地和远端分叉了
Your branch and 'origin/master' have diverged,
and have 2 and 1 different commits each, respectively.
这段话表示:
- 当前在本地
master分支 - 本地
master和远端origin/master的历史已经不是一条直线 - 本地有 2 个远端没有的提交
- 远端有 1 个本地没有的提交
这就是 Git 所说的 diverged,也就是“分叉”。
可以抽象成这样:
A --- B --- C origin/master
\
D --- E master
含义是:
- 远端继续向前走到了
C - 本地从某个共同祖先处分出了自己的两个提交
D、E
这时,本地和远端已经不是简单的“谁领先谁落后”,而是双方都各自前进过。
2. All conflicts fixed but you are still merging
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
这句话很关键。
它说明:
- 你之前已经发起过一次 merge
- merge 过程中曾经发生了 冲突
- 冲突现在已经被你处理好了
- 但是这次合并还没有真正结束,因为你还没执行最后的:
git commit
也就是说,Git 当前还认为仓库处在合并流程中。
3. Changes to be committed
Changes to be committed:
modified: foo/bar/a.js
modified: foo/bar/b.vue
modified: foo/bar/c.vue
这部分表示:
- 这些文件已经被你处理并加入暂存区
- 它们会进入下一次提交
- 在当前语境下,这个“下一次提交”大概率就是 merge commit
换句话说,这些文件很可能就是你处理冲突后的最终结果。
4. Changes not staged for commit
Changes not staged for commit:
modified: .env.development
这表示:
.env.development也被改动了- 但它没有加入暂存区
- 它不会自动进入下一次提交,除非你显式执行
git add
这通常说明:除了 merge 相关改动外,你的工作区里还有额外的本地修改。
二、这个状态是怎么产生的?
下面列几个最常见的形成路径。
情况一:执行了 git pull,出现冲突,解决后还没提交
这是最常见的一种。
可能的操作路径是:
git pull
然后 Git 发现:
- 你本地有自己的提交
- 远端也有新的提交
- 无法直接快进
- 于是开始自动 merge
接着:
- merge 过程中出现冲突
- 你手动修改冲突文件
- 你执行了
git add - 但还没执行
git commit - 同时又改了
.env.development
于是就变成了当前状态。
情况二:手动执行了 git merge origin/master
也有不少人不会直接 pull,而是分开做:
git fetch origin
git merge origin/master
如果这一步触发了冲突,那么之后的流程就一样:
- 解决冲突
git add- 还没
git commit
因此同样会出现“冲突已解决但仍在合并中”的提示。
情况三:合并快结束时,又顺手改了别的文件
这就是当前状态里 .env.development 最可能的来源。
也就是说,merge 相关文件其实已经处理差不多了,但在你提交前又做了其他事,比如:
- 改本地环境配置
- 调试接口地址
- 修改开发端口
- 执行脚本导致配置文件被更新
于是 Git 就会同时展示两种状态:
- merge 结果文件:已暂存
- 本地额外文件:未暂存
情况四:你本来打算提交 merge,但被别的事情打断了
这也是很真实的开发现场:
- pull 或 merge
- 出现冲突
- 解决冲突并
git add - 准备
git commit - 临时去跑项目
- 顺手改了
.env.development - 结果 merge commit 忘了做
最终仓库就停在当前这个中间状态。
情况五:环境文件是被工具自动修改的
.env.development 不一定是手工改的,也可能是:
- 本地脚本自动更新
- 编辑器插件格式化
- 某些开发工具写入默认值
- 切换环境后产生差异
所以从 Git 状态本身,只能确认它“被修改了”,不能武断地断言是谁改的。这点需要结合 git diff .env.development 才能进一步确认。
三、为什么会同时出现 diverged 和 still merging?
很多人会困惑:这两个提示不是重复的吗?
其实不是,它们说的是两个不同维度的状态。
diverged 说的是分支关系
它描述的是:
- 本地
master - 远端
origin/master
这两个分支的提交历史关系
也就是:双方各自都有新提交,已经分叉。
still merging 说的是当前操作流程
它描述的是:
- 你已经开始了一次 merge
- merge 还没通过最终 commit 收尾
也就是:操作进行到一半,还没结束。
两者合起来就是完整故事
把这两部分拼起来,通常就变成:
因为本地和远端分叉了,所以你触发了一次 merge;merge 时产生冲突,冲突虽然已经解决,但 merge commit 还没提交。
这就是当前状态最合理、最常见的解释。
四、为什么 Git 明明说“冲突已解决”,却还不算完成?
因为 Git 判断 merge 是否结束,不是只看文件内容,而是看合并流程元数据。
只要 merge 还没被最终提交,Git 就仍然认为:
- 这次 merge 正在进行
- 仓库还没回到普通状态
简单理解:
- “冲突已解决” 只是说明文件层面已经处理完
- “仍在合并中” 表示流程层面还没闭环
只有执行:
git commit
这次 merge 才真正完成。
五、当前状态的准确含义
如果用更工程化的语言描述,这个仓库当前处于:
- 本地与远端分支已分叉
- 已发起一次合并
- 合并冲突已处理并暂存
- 尚未生成最终 merge commit
- 工作区中还有额外未暂存修改
因此,它不是“仓库坏了”,也不是“冲突没处理完”,而是:
一个很典型的“合并收尾阶段 + 工作区仍有额外改动”的状态。
六、最可能的形成过程
综合这类输出,最常见的真实路径通常是:
# 本地已有自己的提交
# 远端也有新提交
git pull
# 或 git fetch + git merge
# 发生冲突
# 手工修改冲突文件
git add foo/bar/a.js
git add foo/bar/b.vue
git add foo/bar/c.vue
# 此时其实只差最后一步
# git commit
# 但你又改了 .env.development
于是 git status 就会同时告诉你:
- 分支已经 diverged
- merge 还没结束
- 有文件已暂存
- 还有文件未暂存
七、如何验证这个状态是怎么来的?
如果你想进一步确认,不要猜,直接看 Git 记录。
1. 查看最近操作历史
git reflog -10
重点看最近几条里有没有:
pullmergecheckoutreset
这通常能直接还原你最近做过什么。
2. 查看分支图
git log --oneline --graph --decorate --all -20
这可以帮助你看清:
- 本地多出来的 2 个提交是什么
- 远端多出来的 1 个提交是什么
- 当前 HEAD 在什么位置
3. 看暂存区里到底准备提交什么
git diff --cached
这能确认那几个已暂存文件是否就是冲突解决结果。
4. 看环境文件改了什么
git diff .env.development
这样才能判断它是:
- 纯本地配置改动
- 临时调试改动
- 还是本次 merge 的一部分
八、理解这个状态时最容易犯的误区
误区一:以为“冲突已解决”就等于 merge 完成
不是。
冲突解决只是过程中的一步,merge 最终是否完成,要看有没有最后的 commit。
误区二:以为 .env.development 一定和 merge 有关
也不一定。
它可能只是工作区里的额外改动,和冲突文件完全不是一回事。
误区三:以为仓库已经异常,必须 reset
这个状态并不罕见,也不意味着仓库损坏。
大多数时候,它只是一个正常但未收尾的 Git 流程。
九、一个更直观的心智模型
可以把当前状态想象成这样:
- 历史层面:本地和远端已经各走各的,产生分叉
- 操作层面:你正在把两条历史重新合并
- 文件层面:冲突文件已经处理完并放进暂存区
- 工作区层面:你还留着一个额外没处理的本地改动
四者叠加后,就形成了今天这段看起来复杂的 git status。
十、结论
当 Git 同时显示:
Your branch and 'origin/master' have divergedAll conflicts fixed but you are still mergingChanges to be committedChanges not staged for commit
它通常意味着:
你所在分支和远端已经分叉;你发起过一次 merge;冲突已经处理并暂存;但 merge 还没有提交结束;同时工作区里还有额外的未暂存改动。
这不是一个神秘状态,而是一个非常典型的 Git 合并中间态。
理解它的关键,不是只盯着某一行提示,而是把它拆成四件事看:
- 分支关系是否分叉
- merge 是否已发起
- 冲突文件是否已暂存
- 工作区是否还有其他修改
当这四件事都看清楚后,这个状态其实一点都不复杂。
附:文中涉及的常用命令
git status
git reflog -10
git log --oneline --graph --decorate --all -20
git diff
git diff --cached
git diff .env.development
SEO 建议
-
关键词:
- Git still merging
- Git diverged
- All conflicts fixed but you are still merging
- git status 解释
- Git 合并冲突解决后未提交
-
建议描述:
- 解析 Git 中 diverged 与 still merging 同时出现的原因,帮助开发者理解一次未完成 merge 的真实含义。
-
建议标签:
- Git
- 版本控制
- 开发工具
- 合并冲突
- 工程实践
说明
本文基于给出的 git status 输出进行分析,能高概率还原其形成原因,但不能仅凭这一段输出百分之百确定你执行过的具体命令顺序。若需精确复盘,需结合 git reflog 与提交图进一步确认。