Skip to content

6. Resolving Merge Conflicts

drawing

Merge conflicts happen when Git can't automatically combine changes. Don't panic—they're normal and easy to fix!


What is a Merge Conflict?

A conflict occurs when two people edit the same part of the same file and Git doesn't know which version to keep.

git merge — Combining branches (and resolving conflicts)

Once testing is complete, Dr.X merges her branch back into main.

git checkout main
git merge normalization

When conflicts arise — A realistic scenario

While Dr. X was working on log-normalization in the normalization branch, Dr. Y was simultaneously updating the same data_preprocessing.py file on main to add a different scaling method. Now, when Dr. X tries to merge:

error

    Auto-merging data_preprocessing.py
    CONFLICT (content): Merge conflict in data_preprocessing.py
    Automatic merge failed; fix conflicts and then commit the result.

Git cannot automatically decide which changes to keep — just like two scientists editing different parts of the same methods section in a manuscript.

Anatomy of a conflict

Opening data_preprocessing.py, Dr. X sees conflict markers:

def normalize_counts(adata):
    """Normalize raw count data"""
<<<<<<< HEAD
    # Dr. Y's changes on main branch
    sc.pp.scale(adata, max_value=10)
    print("Applied scaling normalization")
=======
    # Dr. X's changes on normalization branch
    sc.pp.log1p(adata)
    print("Applied log-normalization")
>>>>>>> normalization
    return adata

The conflict markers show: - <<<<<<< HEAD: Current branch (main) version - =======: Separator between the two versions - >>>>>>> normalization: Incoming branch version

Resolving the conflict

Dr. X realises both normalizations are valuable and should be applied sequentially. They manually edit the file:

def normalize_counts(adata):
    """Normalize raw count data"""
    # Apply both normalization steps
    sc.pp.log1p(adata)
    sc.pp.scale(adata, max_value=10)
    print("Applied log-normalization followed by scaling")
    return adata

Completing the merge

After resolving all conflicts:

    # Check which files had conflicts
    git status

    # Stage the resolved file
    git add data_preprocessing.py

    # Complete the merge with a commit
    git commit -m "Merge normalization branch: combine log and scale methods"

Conflict prevention tips

  • Communicate with collaborators about which files you're editing
  • Pull frequently to stay synchronized: git pull origin main
  • Keep branches short-lived and focused
  • Use git fetch + git diff origin/main to preview incoming changes
%%{init: {'theme': 'base'}}%%
gitGraph
  commit id: "A: Initial pipeline"
  branch normalization
  checkout normalization
  commit id: "B: Add log-norm"
  checkout main
  commit id: "C: Add scaling"
  merge normalization tag: "Resolved: Both methods"

Advanced: Using merge tools

For complex conflicts, Dr. X can use visual merge tools:

# Configure a merge tool (e.g., VS Code, Meld, or vimdiff)
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'

# Launch the merge tool
git mergetool

This opens a side-by-side comparison, making it easier to see differences and choose the correct resolution.

flowchart TB
  A[Merge conflict detected] --> B{Conflict complexity?}
  B -->|Simple| C[Manual editing]
  B -->|Complex| D[Visual merge tool]
  C --> E[git add file]
  D --> E
  E --> F[git commit]
  F --> G[Merge complete ✓]
  style A fill:#ffe6e6,stroke:#f00
  style G fill:#e6ffe6,stroke:#0f0

Key Takeaways

  • ✅ Conflicts happen when same lines are edited differently
  • ✅ Conflict markers: <<<<<<<, =======, >>>>>>>
  • ✅ Resolution: Edit file → Remove markers → Stage → Commit
  • ✅ Use git merge --abort if you want to cancel
  • ✅ Tools like VS Code make conflicts easier to resolve
  • ✅ Communication with team prevents many conflicts