Skip to content

DevOps Day 33: Resolving a Real-World Merge Conflict

Today's task was a perfect simulation of an everyday scenario for any developer working on a team. I was asked to push some changes, but my push was rejected because a teammate had updated the code in the meantime. This led me down the path of pulling the latest changes, encountering a "merge conflict," and then manually resolving it.

This was an incredibly valuable lesson. A merge conflict sounds scary, but I learned that it's just Git's way of pausing the process and asking a human for help when it can't automatically combine two different sets of changes to the same file. This document is my detailed, first-person guide to that entire troubleshooting and resolution process.

Table of Contents


The Task

My objective was to synchronize my local Git repository with the remote, resolve any conflicts, and fix some content issues before successfully pushing my final changes. The requirements were: 1. Work as user max in the /home/max/story-blog repository on the Storage Server. 2. Attempt to push changes and diagnose the failure. 3. pull the latest changes from the remote. 4. Resolve the resulting merge conflict in the story-index.txt file. 5. The final story-index.txt file must contain the titles for all four stories and a typo (Mooose -> Mouse) must be fixed. 6. Commit the resolved merge and push the final, clean history to the master branch.


My Step-by-Step Solution

The solution required a careful, multi-step process to integrate my changes with my teammate's.

Phase 1: Diagnosing the Problem

  1. I connected to the Storage Server (ssh max@ststor01) and navigated to the repository (cd /home/max/story-blog).
  2. I first tried to push my changes, as instructed.
    git push origin master
    
  3. As expected, the push was rejected with the classic error: ! [rejected] master -> master (fetch first). The hints correctly told me that the remote contained work that I did not have locally.

Phase 2: The Conflict

  1. I followed the hint and ran git pull to fetch and merge the remote changes.
    git pull origin master
    
  2. This is where the real work began. The pull failed to complete automatically and gave me the message: CONFLICT (add/add): Merge conflict in story-index.txt Automatic merge failed; fix conflicts and then commit the result. This told me that both I and another developer had made conflicting changes to the same file.

Phase 3: The Resolution

  1. I opened the conflicted file in a text editor: vi story-index.txt.
  2. Inside, Git had marked the conflicting sections:
    <<<<<<< HEAD
    The Lion and the Mooose
    The Frogs and the Ox
    =======
    The Fox and the Grapes
    The Fourth Story
    >>>>>>> origin/master
    
  3. I manually edited the file to create the final, correct version. This involved:
    • Deleting all the conflict markers (<<<<<<<, =======, >>>>>>>).
    • Combining the lines from both sections.
    • Fixing the "Mooose" typo. The final, clean content looked like this:
      The Lion and the Mouse
      The Frogs and the Ox
      The Fox and the Grapes
      The Fourth Story
      
  4. After saving the file, I had to tell Git that the conflict was resolved. I did this by staging the corrected file.
    git add story-index.txt
    
  5. Finally, I completed the merge by creating a commit. Git had paused the merge, and this commit finalized it.
    git commit
    
    Git opened an editor with a pre-written merge commit message, which I saved.

Phase 4: The Final Push

With the conflict resolved and the merge committed, my local master branch now contained my work, my teammate's work, and the merge commit. It was fully ahead of the remote. 1. I ran the push command one last time.

git push origin master
2. This time, the push was successful, completing the task.


Why Did I Do This? (The "What & Why")

- Rejected Push (fetch first): This is Git's primary safety mechanism for collaboration. It prevents you from accidentally overwriting your teammate's work. If the remote history has moved forward since you last pulled, Git forces you to integrate those new changes into your local branch before you are allowed to push. - git pull: This is the standard command to synchronize your local repository with a remote. It's actually a combination of two other commands: 1. git fetch: This downloads the latest history from the remote server but does not change any of your local files. 2. git merge: After fetching, it automatically tries to merge the downloaded remote branch (e.g., origin/master) into your current local branch (e.g., master). - Merge Conflict: This occurs when the automatic merge fails. A conflict happens when two developers make different changes to the same lines in the same file. Git doesn't know which version is correct, so it stops and asks a human to make the intelligent decision of how to combine the changes.


Deep Dive: The Anatomy of a Merge Conflict

This task was a perfect lesson in how to read and resolve a merge conflict. When a conflict occurs, Git edits the problematic file and inserts conflict markers to show you both versions of the contested content.

[Image of a file with Git merge conflict markers]

<<<<<<< HEAD
The content from YOUR branch (the one you are on) goes here.
=======
The content from the OTHER branch (the one you are merging in) goes here.
>>>>>>> [branch name or commit hash]
- <<<<<<< HEAD: This marks the beginning of the conflicting block. HEAD is a pointer to your current branch, so everything between this line and the ======= is your version of the changes. - =======: This line separates your changes from the incoming changes. - >>>>>>> [branch name]: This marks the end of the conflicting block. Everything between the ======= and this line is the incoming version of the changes from the other branch.

My job as the resolver was to: 1. Open the file. 2. Look at both versions of the content. 3. Decide what the final, correct version should be. This often involves combining elements from both sides, as I did in my solution. 4. Delete all three conflict marker lines (<<<<<<<, =======, >>>>>>>). 5. Save the clean, correct file.


Common Pitfalls

- Force Pushing: A dangerous mistake would be to "solve" the rejected push by using git push --force. This would have overwritten Sarah's work on the server and is a major violation of collaborative etiquette. - Incorrectly Resolving the Conflict: Simply deleting the other person's changes, or leaving the conflict markers in the file, would be incorrect. The goal is to intelligently combine the work from both developers. - Forgetting to add and commit: After manually editing the conflicted file, you must run git add [file] to mark it as resolved, and then git commit to finalize the merge. Forgetting these steps leaves the repository in a conflicted state.


Exploring the Commands I Used

- git push origin master: The command to send my local master branch's commits to the remote named origin. It failed initially because my local branch was out of date. - git pull origin master: The command to synchronize. It fetches the latest history from the remote master branch and merges it into my local master branch. - vi story-index.txt: The standard Linux text editor I used to open the conflicted file, view the conflict markers, and edit the content to its final, correct state. - git add story-index.txt: After resolving the conflict, this command tells Git, "I have fixed this file; please stage it for the next commit." This marks the conflict as resolved. - git commit: When run after a conflict has been resolved, this command creates a new "merge commit" to finalize the process, combining the two histories.