Git Conflict Resolution

1. 这篇文章解决什么问题?

Git 冲突不是异常情况,而是多人协作和分支开发里的正常现象。

常见问题包括:

text 复制代码
1. 为什么会产生冲突?
2. 冲突文件里的 <<<<<<<、=======、>>>>>>> 是什么?
3. merge 冲突怎么解决?
4. rebase 冲突怎么解决?
5. 解决冲突后为什么还要 git add?
6. 如果不想继续 merge 或 rebase,怎么取消?

这篇只讲冲突处理流程。

mergerebasepull 的概念放在 05-merge-rebase-pull.md 里理解。


2. 冲突为什么会发生?

Git 自动合并的前提是:

text 复制代码
两边修改的位置不冲突
或者 Git 能判断应该保留哪些内容

如果两个分支都修改了同一个文件的同一块内容,Git 就不敢替你决定。

例如 main 上把一行改成:

cpp 复制代码
int timeout = 30;

功能分支上把同一行改成:

cpp 复制代码
int timeout = 60;

这时 Git 不知道最终应该是 30 还是 60,就会产生冲突。


3. 冲突发生时 Git 在做什么?

假设当前历史是:

text 复制代码
A -- B -- C
          |
        main
          \
           D -- E
                |
          feature/cache

main 上执行:

bash 复制代码
git merge feature/cache

如果两边改了同一块内容,Git 会停下来:

text 复制代码
Auto-merging config.cpp
CONFLICT (content): Merge conflict in config.cpp
Automatic merge failed; fix conflicts and then commit the result.

这时仓库处于一个"合并进行中"的状态。

需要做三件事:

text 复制代码
1. 打开冲突文件
2. 手动决定最终内容
3. git add 标记冲突已解决

4. 冲突标记怎么看?

冲突文件里通常会出现:

text 复制代码
marker: <<<<<<< HEAD
int timeout = 30;
marker: =======
int timeout = 60;
marker: >>>>>>> feature/cache

真实文件里不会有 marker: 前缀,这里只是为了避免 Git 把笔记示例误判成未解决冲突。

含义是:

text 复制代码
上半段:<<<<<<< HEAD 到 ======= 之间,是当前分支的内容
下半段:======= 到 >>>>>>> feature/cache 之间,是被合并进来的分支内容

如果你当前在 main 上执行:

bash 复制代码
git merge feature/cache

那么:

text 复制代码
HEAD 通常表示 main 当前内容
feature/cache 表示正在合并进来的内容

5. 冲突文件应该怎么改?

解决冲突不是删除某一边那么简单,而是决定最终代码应该长什么样。

例如上面的冲突,可以改成:

cpp 复制代码
int timeout = 60;

也可以改成:

cpp 复制代码
int timeout = loadTimeoutFromConfig();

关键是:

text 复制代码
最终文件里不能留下 <<<<<<<、=======、>>>>>>>
最终代码必须能表达正确业务逻辑

解决后执行:

bash 复制代码
git status
git add config.cpp

git add 在这里的含义不是"准备提交新功能",而是:

text 复制代码
告诉 Git:这个文件的冲突我已经处理完了

6. merge 冲突的完整流程

典型流程:

bash 复制代码
git checkout main
git merge feature/cache

如果出现冲突:

bash 复制代码
git status

打开冲突文件,修改成最终内容。

然后:

bash 复制代码
git add config.cpp
git status
git commit

如果这是普通 merge,最后的 git commit 会生成一个 merge commit。

有时 Git 会自动准备好 commit message,直接保存即可。


7. rebase 冲突的完整流程

典型流程:

bash 复制代码
git checkout feature/cache
git rebase main

如果某个提交应用时发生冲突,Git 会停下来。

解决文件后执行:

bash 复制代码
git add config.cpp
git rebase --continue

如果后面的提交继续冲突,就继续重复:

text 复制代码
改冲突文件
git add
git rebase --continue

这就是 05 里说的:

text 复制代码
merge 冲突像一次性结算
rebase 冲突像按提交分期结算

8. ours 和 theirs 怎么理解?

冲突时经常会看到:

bash 复制代码
git checkout --ours config.cpp
git checkout --theirs config.cpp

merge 中通常可以这样理解:

text 复制代码
ours   当前分支的版本
theirs 被合并进来的分支版本

例如当前在 main 上:

bash 复制代码
git merge feature/cache

那么:

text 复制代码
ours   main
theirs feature/cache

如果你确定保留当前分支版本:

bash 复制代码
git checkout --ours config.cpp
git add config.cpp

如果你确定保留对方分支版本:

bash 复制代码
git checkout --theirs config.cpp
git add config.cpp

注意:

text 复制代码
不要只因为命令方便就整文件保留一边
很多冲突需要把两边逻辑合在一起

9. rebase 里的 ours 和 theirs 容易反直觉

rebase 过程中,ourstheirs 容易让人迷糊。

因为 rebase 的过程是:

text 复制代码
先切到目标基底
再把你的提交一个一个应用上去

所以在 rebase 冲突里,ours 往往表示当前基底那边,theirs 往往表示正在被重新应用的那个提交。

新手不建议在 rebase 冲突里盲目使用:

bash 复制代码
git checkout --ours
git checkout --theirs

更稳的方式是:

text 复制代码
打开文件
读冲突上下文
手动改成最终想要的代码

10. 不想继续 merge 怎么办?

如果 merge 到一半发现不想继续了:

bash 复制代码
git merge --abort

它会尝试回到 merge 之前的状态。

常见场景:

text 复制代码
冲突太多,想换一种合并方式
发现合错分支了
还没准备好处理这些冲突

执行后再看:

bash 复制代码
git status

确认仓库已经回到正常状态。


11. 不想继续 rebase 怎么办?

如果 rebase 到一半不想继续:

bash 复制代码
git rebase --abort

它会回到 rebase 开始之前。

如果已经解决了当前冲突,想继续:

bash 复制代码
git rebase --continue

如果想跳过当前这个提交:

bash 复制代码
git rebase --skip

--skip 要谨慎,因为它表示:

text 复制代码
当前这个提交不要了

12. 冲突解决后要做什么检查?

解决冲突后,不要只看 Git 是否通过,还要确认代码真的正确。

推荐顺序:

bash 复制代码
git status
git diff --cached

然后根据项目情况运行:

bash 复制代码
cmake --build build
ctest --test-dir build

或者至少运行当前模块的编译和测试。

冲突解决最容易出问题的地方不是语法,而是:

text 复制代码
两边逻辑都保留了,但组合后语义不对
删掉冲突标记了,但误删了一段必要逻辑
代码能编译,但配置、路径、条件判断错了

13. 减少冲突的习惯

冲突不能完全避免,但可以减少。

比较实用的习惯:

text 复制代码
1. 功能分支不要拖太久
2. 经常 fetch,然后让自己的分支跟上 main
3. 不要在一个提交里混合太多无关修改
4. 格式化代码和业务修改尽量分开提交
5. 修改公共头文件、配置文件时更谨慎
6. 合并前先看 git status,保证工作区干净

尤其是 C++ 项目里,下面这些文件容易引发多人冲突:

text 复制代码
CMakeLists.txt
公共头文件
配置文件
README.md
接口定义文件

这些文件改动前最好先同步最新主分支。


14. 总结

冲突的本质是 Git 无法自动判断最终内容。

解决冲突时,先用 git status 找到冲突文件,再手动改成正确代码,最后用 git add 标记已解决;如果方向错了,用 merge --abortrebase --abort 退回去。

相关推荐
Volunteer Technology6 分钟前
Flink的DataStream分区操作
大数据·linux·flink
米云科技17 分钟前
小红书客服软件支持多账号吗?米多客高效解决跨账号管理难题
大数据·人工智能
曾阿伦33 分钟前
Elasticsearch Analyzer 分析器开发指南
大数据·elasticsearch·搜索引擎
科技道人36 分钟前
Launcher allapps界面顶部推荐的app
git·github·launcher·allapps
庞白OS1 小时前
一次ds对话
大数据·人工智能
云水一下1 小时前
平行宇宙的魔法——Git 分支与合并的艺术
git
OCR_133716212751 小时前
技术选型干货:通用大模型与垂直OCR模型算力、成本、资源深度对比
大数据·人工智能
superantwmhsxx1 小时前
GPT-5.5 科研助手实战:从假设提出到实验验证的全流程效果展示
大数据·人工智能·gpt
袋鼠云数栈2 小时前
数栈 V7.0 多模态数据智能平台:打造 AI-Ready 的企业数据底座
大数据·数据结构·数据库·人工智能·数据治理·多模态
风途科技~2 小时前
告别外观辨鸟误区,鸟类性别检测仪实现禽类性别判定
大数据·人工智能