Why Git’s diff3 merge conflicts are confusing

It’s popular (and good!) advice to tell people to set git config --global merge.conflictStyle diff3 (“Take the pain out of git conflict resolution: use diff3”), but I’ve always found diff3-style merge conflicts pretty confusing. I’ve never managed to internalize if the top section is from “my branch” or “their branch”. It turns out there’s a reason for this — the first section in a diff3 merge conflict is your branch in a merge, but their branch in a rebase!

If you have feature-branch checked out and you want to update it to the current main branch, here’s how you’d read a diff3 conflict:

<<<<<<< HEAD
    The "current commit".
    For `git rebase main`, this will be the code in `main`.
        (Because `HEAD` is on top of `main`.)
    For `git merge main`, this will be the code in `feature-branch`.
        (Because `HEAD` is on top of `feature-branch`, and `main` is being
        merged _into_ it.)
||||||| parent of ea45005
    The conflicting lines before either branch changed them.
=======
    For `git rebase main`, this will be the code in `feature-branch`.
        (Because you're stacking the changes in `feature-branch` on top of
        `main`.)
    For `git merge main`, this will be the code in `main`.
        (Because you're adding the changes in `main` to `feature-branch`.)
>>>>>>> ea45005

PS: Try git config --global merge.conflictStyle zdiff3, which moves as many lines as possible out of the merge conflict.