What's Actually Happening

You're attempting to merge a branch, but Git cannot automatically resolve the conflicts between your changes and the incoming changes. The merge stops mid-process, leaving conflict markers in your files. In some cases, subsequent operations fail because the repository is in an unresolved merge state.

The Error You'll See

During a merge:

bash
Auto-merging src/app.js
CONFLICT (content): Merge conflict in src/app.js
Automatic merge failed; fix conflicts and then commit the result.

When trying to commit without resolving:

bash
error: Committing is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add <file>'
hint: to mark as resolved and use 'git commit' to finalize the merge.

When trying other operations during a merge:

bash
fatal: You have not concluded your merge (MERGE_HEAD exists).
Please, commit your changes before you merge.

Why This Happens

Git merge conflicts occur when: - The same lines are modified differently in both branches - One branch deletes a file while the other modifies it - Both branches add files with the same name but different content - Binary files are modified in both branches - File renames conflict with modifications

Git marks these conflicts but cannot automatically decide which version to keep.

Step 1: Identify Conflicted Files

Check the current merge status:

bash
git status

Look for files marked as "both modified" or "unmerged":

bash
Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified:   src/app.js
    both modified:   config/settings.json
    deleted by them: src/old-module.js

Step 2: View Conflict Details

For a detailed view of conflicts:

bash
git diff --name-only --diff-filter=U

To see the actual conflicts in a file:

bash
git diff src/app.js

Step 3: Understand Conflict Markers

Open a conflicted file to see markers:

bash
<<<<<<< HEAD
const value = 100;
=======
const value = 200;
>>>>>>> feature-branch
  • <<<<<<< HEAD marks your current branch's version
  • ======= separates the versions
  • >>>>>>> feature-branch marks the incoming branch's version

Step 4: Resolve Conflicts Manually

Edit each conflicted file, removing markers and keeping the correct code:

bash
nano src/app.js

Choose one version, combine both, or write something new:

javascript
// Combined solution
const value = process.env.PRODUCTION ? 200 : 100;

After editing, remove all conflict markers.

Step 5: Stage Resolved Files

Mark each file as resolved:

bash
git add src/app.js
git add config/settings.json

For deleted file conflicts, choose to keep or remove:

```bash # Keep the file (their deletion) git rm src/old-module.js

# Or keep your version git add src/old-module.js ```

Step 6: Use Git Tools for Resolution

Git provides tools to help resolve conflicts:

Checkout one side completely:

```bash # Keep your version git checkout --ours src/app.js

# Keep their version git checkout --theirs src/app.js ```

Or use the merge tool:

bash
git mergetool

Step 7: Verify All Conflicts Are Resolved

Check for any remaining conflicts:

bash
git diff --check

No output means all conflicts are resolved.

Check staging status:

bash
git status

All conflicted files should now be in "Changes to be committed".

Step 8: Complete the Merge

Commit the merge resolution:

bash
git commit -m "Merge feature-branch into main, resolve conflicts in app.js and settings"

Git automatically generates a merge commit message with details about the merged branches.

Step 9: Handle Aborted Merges

If you need to start over:

bash
git merge --abort

This cancels the merge and returns to the pre-merge state.

If abort doesn't work (older Git versions):

bash
git reset --hard HEAD

Verify the Fix

Confirm the merge is complete:

bash
git status

You should see:

bash
On branch main
nothing to commit, working tree clean

Verify the merge commit:

bash
git log --oneline -3

You should see your merge commit in the history.

Test that the code works:

bash
npm test
# or
make test

For future merges, consider using git rerere (reuse recorded resolution) to automatically apply previous conflict resolutions:

bash
git config --global rerere.enabled true