Appearance
解决冲突
概述
合并冲突是团队协作中常见的情况。当两个分支修改了同一文件的同一位置时,Git 无法自动合并,需要人工干预解决冲突。
冲突产生原因
内容冲突
两个分支修改了同一文件的同一行。
bash
# 分支 A 修改了 file.txt 的第 10 行
echo "Version A" >> file.txt
# 分支 B 也修改了 file.txt 的第 10 行
echo "Version B" >> file.txt
# 合并时产生冲突
git merge branch-b
# CONFLICT (content): Merge conflict in file.txt文件名冲突
两个分支对同一文件进行了不同的重命名或删除操作。
bash
# 分支 A 重命名文件
git mv file.txt file-a.txt
# 分支 B 重命名文件
git mv file.txt file-b.txt
# 合并时产生冲突
git merge branch-b
# CONFLICT (rename/rename): file.txt renamed to file-a.txt in HEAD and to file-b.txt in branch-b目录冲突
两个分支创建了同名但类型不同的条目。
bash
# 分支 A 创建文件
touch lib/module
# 分支 B 创建同名目录
mkdir -p lib/module
# 合并时产生冲突
git merge branch-b
# CONFLICT (file/directory): directory in the way of file识别冲突
查看冲突状态
bash
# 合并后查看状态
git status
# 输出:
# Unmerged paths:
# (use "git add <file>..." to mark resolution)
# both modified: src/main.js
# deleted by them: src/old.js
# added by them: src/new.js冲突状态说明
| 状态 | 含义 |
|---|---|
both modified | 双方都修改了同一文件 |
deleted by them | 当前分支修改,对方分支删除 |
deleted by us | 当前分支删除,对方分支修改 |
added by them | 对方分支添加的文件与当前冲突 |
added by us | 当前分支添加的文件与对方冲突 |
both added | 双方都添加了同一文件 |
both deleted | 双方都删除了同一文件 |
查看冲突文件列表
bash
# 列出所有冲突文件
git diff --name-only --diff-filter=U
# 列出冲突文件及状态
git diff --name-status --diff-filter=U手动解决冲突
理解冲突标记
# 冲突文件示例
function greet() {
<<<<<<< HEAD
console.log("Hello from main");
=======
console.log("Hello from feature");
>>>>>>> feature
}标记说明:
<<<<<<< HEAD(7 个<):当前分支(HEAD)的内容开始=======(7 个=):分隔线,分隔两个版本>>>>>>> feature(7 个>):被合并分支的内容结束
解决步骤
bash
# 1. 打开冲突文件
vim src/main.js
# 2. 找到冲突标记
# 3. 编辑文件,解决冲突
# 选择保留的内容,删除冲突标记
# 4. 保存文件
# 5. 标记冲突已解决
git add src/main.js
# 6. 继续处理其他冲突文件
# 7. 完成合并
git commit解决示例
原始冲突:
javascript
function greet() {
<<<<<<< HEAD
console.log("Hello from main");
=======
console.log("Hello from feature");
>>>>>>> feature
}解决方案 1:保留当前分支
javascript
function greet() {
console.log("Hello from main");
}解决方案 2:保留被合并分支
javascript
function greet() {
console.log("Hello from feature");
}解决方案 3:合并两者
javascript
function greet() {
console.log("Hello from main");
console.log("Hello from feature");
}解决方案 4:全新内容
javascript
function greet() {
console.log("Hello from both branches");
}复杂冲突处理
bash
# 多处冲突
# 文件中可能有多个冲突块
<<<<<<< HEAD
console.log("First conflict - main");
=======
console.log("First conflict - feature");
>>>>>>> feature
// 其他代码...
<<<<<<< HEAD
console.log("Second conflict - main");
=======
console.log("Second conflict - feature");
>>>>>>> feature使用合并工具
内置合并工具
bash
# 启动合并工具
git mergetool
# Git 会依次打开每个冲突文件配置合并工具
bash
# 查看可用的合并工具
git mergetool --tool-help
# 配置使用 vimdiff
git config --global merge.tool vimdiff
# 配置使用 VS Code
git config --global merge.tool code
git config --global mergetool.code.cmd 'code --wait $MERGED'
# 配置使用其他工具
git config --global merge.tool meld # Linux
git config --global merge.tool opendiff # macOS
git config --global merge.tool kdiff3 # Cross-platform使用 vimdiff
bash
# vimdiff 显示四个窗口
# +----------------+----------------+
# | LOCAL | REMOTE |
# | (当前分支版本) | (被合并分支版本)|
# +----------------+----------------+
# | MERGED (底部,编辑窗口) |
# +---------------------------------+
# | BASE (共同祖先) |
# +---------------------------------+
# 常用命令
# :diffg LO - 使用 LOCAL 版本
# :diffg RE - 使用 REMOTE 版本
# :diffg BA - 使用 BASE 版本
# :wqa - 保存并退出使用 VS Code
bash
# VS Code 提供可视化冲突解决界面
# 点击 "Accept Current Change" 保留当前分支
# 点击 "Accept Incoming Change" 保留被合并分支
# 点击 "Accept Both Changes" 保留两者
# 点击 "Compare Changes" 查看差异快速解决策略
选择特定版本
bash
# 使用当前分支版本
git checkout --ours file.txt
# 使用被合并分支版本
git checkout --theirs file.txt
# 使用 git restore(Git 2.23+)
git restore --ours file.txt
git restore --theirs file.txt使用合并策略选项
bash
# 合并时优先使用当前分支
git merge -X ours feature
# 合并时优先使用被合并分支
git merge -X theirs feature
# 注意:这只会自动解决冲突,其他修改仍会合并批量解决
bash
# 批量使用当前分支版本
git checkout --ours .
git add .
# 批量使用被合并分支版本
git checkout --theirs .
git add .中止合并
取消合并
bash
# 中止合并,恢复到合并前状态
git merge --abort
# 如果已经解决部分冲突,--abort 会撤销所有更改重置到合并前
bash
# 使用 reset 回退
git reset --hard HEAD
# 或使用 ORIG_HEAD
git reset --hard ORIG_HEAD冲突预防
定期同步
bash
# 在功能分支上定期合并主分支
git checkout feature
git fetch origin
git merge origin/main
# 或使用变基
git rebase origin/main小步提交
bash
# 频繁提交小的、原子性的更改
# 减少单次提交的修改范围
# 降低冲突概率团队协调
bash
# 避免多人同时修改同一文件
# 使用代码所有权规则
# 进行充分的代码审查使用 .gitattributes
bash
# .gitattributes 文件
# 定义合并策略
# 总是使用当前分支版本
config.lock merge=ours
# 定义自定义合并驱动
*.js merge=js-merge总结
- 冲突是团队协作的正常现象
- 理解冲突标记是解决冲突的基础
- 使用合并工具提高效率
- 定期同步可以减少冲突
- 小步提交降低冲突影响
下一步
学习完解决冲突后,建议继续学习:
- 变基操作 - 学习另一种整合方式
- Merge vs Rebase - 比较两种整合方式
