Git - Handling Conflicts
Git - Handling Merge Conflicts
Section titled “Git - Handling Merge Conflicts”Merge conflicts occur when Git cannot automatically combine changes from different commits or branches. This typically happens when two developers modify the same lines in the same file, or if one developer deletes a file that another developer has modified. This section demonstrates a common conflict scenario and its resolution.
Scenario Setup: Concurrent Changes
Section titled “Scenario Setup: Concurrent Changes”Let’s assume our project has a file src/str_ops.c with a function w_strlen (a wide-character string length function). Jerry is working on a feature branch wchar_enhancements and Tom is working on the main branch. Both decide to rename w_strlen.
Jerry’s Changes on wchar_enhancements Branch
Section titled “Jerry’s Changes on wchar_enhancements Branch”Jerry renames w_strlen to 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 # Example modification
[jerry@devbox project]$ git diff src/str_ops.cDiff output (simplified):
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 commits and pushes his branch:
[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’s Changes on main Branch
Section titled “Tom’s Changes on main Branch”Meanwhile, Tom, working on the main branch, renames the same w_strlen function to my_wc_strlen and adds a comment.
[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 # Example modification[tom@devbox project]$ # (Tom also adds a comment above the function)
[tom@devbox project]$ git diff src/str_ops.cDiff output (simplified):
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,8 @@ #include <wchar.h>
-size_t w_strlen(const wchar_t *s)+/* Custom wide character strlen function */+size_t my_wc_strlen(const wchar_t *s) { const wchar_t *p = s; // ...Tom commits and pushes his changes to 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 mainCreating and Encountering a Conflict
Section titled “Creating and Encountering a Conflict”Now, let’s say Jerry (still on his wchar_enhancements branch) adds another function, my_wstrchr, to src/str_ops.c, commits, and pushes it to his wchar_enhancements branch. This change is independent of the rename for now.
[jerry@devbox project]$ # (Jerry adds my_wstrchr to src/str_ops.c on wchar_enhancements)[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_enhancementsLater, Tom decides to merge Jerry’s wchar_enhancements branch into main to integrate the new features. He first fetches the latest changes:
[tom@devbox project]$ git checkout main[tom@devbox project]$ git fetch originNow Tom tries to merge origin/wchar_enhancements into his local main branch:
[tom@devbox project]$ git merge origin/wchar_enhancementsThis command will likely result in a conflict because both branches modified the w_strlen function name and surrounding lines differently:
Auto-merging src/str_ops.cCONFLICT (content): Merge conflict in src/str_ops.cAutomatic merge failed; fix conflicts and then commit the result.Resolving the Conflict
Section titled “Resolving the Conflict”Git has modified src/str_ops.c to include conflict markers. Tom opens the file and sees something like this:
#include <wchar.h>
<<<<<<< HEAD/* Custom wide character strlen function */size_t my_wc_strlen(const wchar_t *s)=======wchar_t *my_wstrchr(wchar_t *ws, wchar_t wc){ // ... implementation of my_wstrchr ...}
size_t my_wstrlen(const wchar_t *s)>>>>>>> origin/wchar_enhancements{ const wchar_t *p = s; // ...Explanation of markers:
<<<<<<< HEAD: Marks the beginning of the conflicting changes from the current branch (main).=======: Separates the changes frommainand the incoming branch.>>>>>>> origin/wchar_enhancements: Marks the end of the conflicting changes from theorigin/wchar_enhancementsbranch.
Tom needs to manually edit this section to resolve the conflict. He decides to:
- Keep Jerry’s function name
my_wstrlen. - Keep his own comment
/* Custom wide character strlen function */. - Keep Jerry’s new
my_wstrchrfunction.
After editing, the resolved section in src/str_ops.c looks like this:
#include <wchar.h>
wchar_t *my_wstrchr(wchar_t *ws, wchar_t wc){ // ... implementation of my_wstrchr ...}
/* Custom wide character strlen function */size_t my_wstrlen(const wchar_t *s){ const wchar_t *p = s; // ...Tom then stages the resolved file and commits the merge:
[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 opens an editor with a pre-filled merge commit message, e.g.:# Merge remote-tracking branch 'origin/wchar_enhancements'## Conflicts:# src/str_ops.c## Tom saves and closes the editor.The merge commit output:
[main 6b1ac36] Merge remote-tracking branch 'origin/wchar_enhancements'Tom has successfully resolved the conflict and merged the changes. His local main branch now contains the integrated work. He can now push this to the remote main branch:
[tom@devbox project]$ git push origin mainHandling conflicts is a crucial skill in collaborative Git workflows. Using a visual merge tool can also help in resolving complex conflicts. For more information, refer to Git’s documentation on resolving merge conflicts.