Git - 冲突处理
Git - 处理合并冲突
Section titled “Git - 处理合并冲突”当 Git 无法自动合并来自不同 commit(提交)或 branch(分支)的更改时,就会发生合并冲突(Merge conflicts)。这种情况通常发生在两个开发者修改了同一文件中的同一行代码,或者一个开发者删除了另一个开发者修改过的文件。本节演示了一个常见的冲突场景及其解决方法。
场景设置:并发更改
Section titled “场景设置:并发更改”假设我们的项目有一个文件 src/str_ops.c,其中包含一个函数 w_strlen(一个宽字符字符串长度函数)。Jerry 正在一个特性分支 wchar_enhancements 上工作,而 Tom 正在 main 分支上工作。两人都决定重命名 w_strlen。
Jerry 在 wchar_enhancements 分支上的更改
Section titled “Jerry 在 wchar_enhancements 分支上的更改”Jerry 将 w_strlen 重命名为 my_wstrlen。
[jerry@devbox project]$ git checkout -b wchar_enhancementsSwitched to a new branch 'wchar_enhancements'
[jerry@devbox project]$ sed -i 's/w_strlen/my_wstrlen/g' src/str_ops.c # 示例修改
[jerry@devbox project]$ git diff src/str_ops.cDiff 输出(简化):
diff --git a/src/str_ops.c b/src/str_ops.c--- a/src/str_ops.c+++ b/src/str_ops.c@@ -10,7 +10,7 @@ #include <wchar.h>
-size_t w_strlen(const wchar_t *s)+size_t my_wstrlen(const wchar_t *s) { const wchar_t *p = s; // ...Jerry 提交(commit)并推送(push)他的分支:
[jerry@devbox project]$ git add src/str_ops.c[jerry@devbox project]$ git commit -m "Rename w_strlen to my_wstrlen on feature branch"[wchar_enhancements 3789fe8] Rename w_strlen to my_wstrlen on feature branch 1 file changed, 1 insertion(+), 1 deletion(-)
[jerry@devbox project]$ git push origin wchar_enhancementsTom 在 main 分支上的更改
Section titled “Tom 在 main 分支上的更改”与此同时,Tom 在 main 分支上工作,将同一个 w_strlen 函数重命名为 my_wc_strlen 并添加了一个注释。
[tom@devbox project]$ git checkout mainSwitched to branch 'main'Your branch is up to date with 'origin/main'.
[tom@devbox project]$ sed -i 's/w_strlen/my_wc_strlen/g' src/str_ops.c # 示例修改[tom@devbox project]$ # (Tom 还在函数上方添加了一个注释)
[tom@devbox project]$ git diff src/str_ops.cDiff 输出(简化):
diff --git a/src/str_ops.c b/src/str_ops.cindex c2f1477..f1f7e4e 100644--- a/src/str_ops.c+++ b/src/str_ops.c@@ -10,7 +10,8 @@ #include <wchar.h>
-size_t w_strlen(const wchar_t *s)+/* 自定义的宽字符 strlen 函数 */+size_t my_wc_strlen(const wchar_t *s) { const wchar_t *p = s; // ...Tom 提交并推送他的更改到 main:
[tom@devbox project]$ git add src/str_ops.c[tom@devbox project]$ git commit -m "Rename w_strlen to my_wc_strlen and add comment"[main ad4b530] Rename w_strlen to my_wc_strlen and add comment 1 file changed, 2 insertions(+), 1 deletion(-)
[tom@devbox project]$ git push origin main制造并遭遇冲突
Section titled “制造并遭遇冲突”现在,假设 Jerry(仍然在他的 wchar_enhancements 分支上)在 src/str_ops.c 中添加了另一个函数 my_wstrchr,然后提交并推送到他的 wchar_enhancements 分支。目前,这个更改与之前的重命名是独立的。
[jerry@devbox project]$ # (Jerry 在 wchar_enhancements 分支上的 src/str_ops.c 中添加 my_wstrchr)[jerry@devbox project]$ git add src/str_ops.c[jerry@devbox project]$ git commit -m "Add my_wstrchr function"[wchar_enhancements 9d201a9] Add my_wstrchr function 1 file changed, 10 insertions(+)
[jerry@devbox project]$ git push origin wchar_enhancements后来,Tom 决定将 Jerry 的 wchar_enhancements 分支合并到 main 中,以集成新功能。他首先拉取最新的更改:
[tom@devbox project]$ git checkout main[tom@devbox project]$ git fetch origin现在 Tom 尝试将 origin/wchar_enhancements 合并到他本地的 main 分支:
[tom@devbox project]$ git merge origin/wchar_enhancements这个命令很可能会导致冲突,因为两个分支以不同的方式修改了 w_strlen 函数名及其附近的行:
Auto-merging src/str_ops.cCONFLICT (content): Merge conflict in src/str_ops.cAutomatic merge failed; fix conflicts and then commit the result.Git 已经修改了 src/str_ops.c 文件,并加入了冲突标记。Tom 打开文件,会看到类似这样的内容:
#include <wchar.h>
<<<<<<< HEAD/* 自定义的宽字符 strlen 函数 */size_t my_wc_strlen(const wchar_t *s)=======wchar_t *my_wstrchr(wchar_t *ws, wchar_t wc){ // ... my_wstrchr 的实现 ...}
size_t my_wstrlen(const wchar_t *s)>>>>>>> origin/wchar_enhancements{ const wchar_t *p = s; // ...标记解释:
<<<<<<< HEAD: 标记当前分支(main)的冲突更改的开始。=======: 分隔来自main分支和传入分支的更改。>>>>>>> origin/wchar_enhancements: 标记来自origin/wchar_enhancements分支的冲突更改的结束。
Tom 需要手动编辑此部分来解决冲突。他决定:
- 保留 Jerry 的函数名
my_wstrlen。 - 保留他自己的注释
/* Custom wide character strlen function */。 - 保留 Jerry 新添加的
my_wstrchr函数。
编辑后,src/str_ops.c 中已解决冲突的部分看起来像这样:
#include <wchar.h>
wchar_t *my_wstrchr(wchar_t *ws, wchar_t wc){ // ... my_wstrchr 的实现 ...}
/* 自定义的宽字符 strlen 函数 */size_t my_wstrlen(const wchar_t *s){ const wchar_t *p = s; // ...然后 Tom 暂存(stage)已解决的文件,并提交(commit)合并结果:
[tom@devbox project]$ git statusOn branch mainYour branch is ahead of 'origin/main' by 1 commit. (use "git push" to publish your local commits)
You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge)
Unmerged paths: (use "git add <file>..." to mark resolution) both modified: src/str_ops.c
no changes added to commit (use "git add" and/or "git commit -a")
[tom@devbox project]$ git add src/str_ops.c
[tom@devbox project]$ git commit# Git 会打开一个编辑器,其中包含预填充的合并提交消息,例如:# Merge remote-tracking branch 'origin/wchar_enhancements'## Conflicts:# src/str_ops.c## Tom 保存并关闭编辑器。合并提交输出:
[main 6b1ac36] Merge remote-tracking branch 'origin/wchar_enhancements'Tom 成功解决了冲突并合并了更改。他本地的 main 分支现在包含了集成后的工作。他现在可以将这些更改推送到远程的 main 分支:
[tom@devbox project]$ git push origin main处理冲突是 Git 协作工作流中至关重要的技能。使用可视化合并工具(visual merge tool)也有助于解决复杂的冲突。有关更多信息,请参考 Git 关于解决合并冲突的文档。