You ran git merge feature/design-refresh and everything looked fine until Git printed CONFLICT (content): Merge conflict in assets/logo.png and halted. Opening the file in your editor is useless — it shows garbage bytes, not <<<<<<< HEAD markers. Running git mergetool launches a hex editor that isn’t helpful either. Binary files (images, compiled artifacts, SQLite databases, .xlsx files) cannot be line-diffed, so Git refuses to guess which side is “correct” and leaves the decision entirely to you. The resolution is fast once you know which command to reach for, but first you need to identify why the conflict happened and which version you actually want.
Common causes
Ordered by hit rate, highest first.
1. Both branches modified the same binary independently
Two developers each updated assets/logo.png on their own branches — one resized it, one changed the colors. Git sees two different byte sequences for the same path and cannot auto-merge them.
How to spot it: Run git log --oneline --all -- assets/logo.png. You will see two separate commits, each on a different branch, touching the same file after the branch point.
2. One branch deleted the file, the other modified it
A developer removed an outdated .dll on main while another branch added a newer version of the same .dll. Git reports a “modify/delete” conflict.
How to spot it: git status shows deleted by us or deleted by them next to the file path.
3. Auto-generated binary was committed to both branches
Build artifacts (*.pyc, compiled .so, bundled .js.map over a threshold) were committed to both branches at different points in history. Neither version is canonical — you actually want the file out of the repo entirely.
How to spot it: The file extension matches something a .gitignore rule should be catching. Check with git check-ignore -v <file>.
4. Git LFS pointer vs. actual bytes mismatch
One side stored the file as a real blob; the other stored an LFS pointer. Git sees two completely different byte sequences and marks a conflict even though logically only one person touched the “real” file.
How to spot it: cat .git/MERGE_HEAD exists, and git lfs status shows the file under “Git LFS objects to be committed.”
5. File encoding difference
A .docx or .pdf was re-saved by an application that changes internal compression or metadata, producing different bytes even though the human-visible content is identical.
How to spot it: git diff --stat HEAD MERGE_HEAD -- <file> shows a large binary delta despite no intentional edits.
6. Submodule recorded as binary in older Git versions
Very old Git clients sometimes serialize a submodule .gitmodules entry as binary. Upgrading Git resolves this, but during the merge it looks like a binary conflict.
How to spot it: file <conflicted-path> returns ASCII text on one machine but the conflict persists on another with an older Git version.
Shortest path to fix
Step 1: Create a safety backup tag before touching anything
git tag backup/before-binary-fix
This gives you a one-command escape hatch if you pick the wrong version.
Step 2: Identify which version you want
# See the "ours" (current branch) version
git show :2:<path/to/file> > ours_version.bin
# See the "theirs" (incoming branch) version
git show :3:<path/to/file> > theirs_version.bin
Open both files in the appropriate application and decide which is correct.
Step 3: Accept one side explicitly
# Keep the current branch's version
git checkout --ours -- assets/logo.png
# OR keep the incoming branch's version
git checkout --theirs -- assets/logo.png
Step 4: Stage the resolution and continue
git add assets/logo.png
git merge --continue --no-edit
Step 5: Handle the modify/delete case
# If you want to keep the file (overriding the delete)
git checkout --theirs -- assets/logo.png
git add assets/logo.png
# If you want to remove the file (accepting the delete)
git rm assets/logo.png
git merge --continue --no-edit
Step 6: Remove stale temp files
rm -f ours_version.bin theirs_version.bin
git tag -d backup/before-binary-fix # optional cleanup after confirming the merge is good
Prevention
- Add all generated binary extensions to
.gitignorebefore any developer commits them:*.pyc,*.class,*.o,*.so,dist/**,build/**. - Set up Git LFS for large binaries (
git lfs track "*.png" "*.psd" "*.ai") so LFS handles merges as pointer text files. - Use a merge driver for specific binary types in
.gitattributes— for example*.xlsx merge=oursto always prefer the current branch. - Store design source files (Figma exports, PSD) in an asset management system instead of the repo.
- Establish a team convention: only one person owns binary assets on a given branch to avoid simultaneous edits.
- Enable branch protection rules that require PR reviews before merging branches that touch binary asset directories.
- For SQLite files, switch to a plaintext migration format (SQL scripts) and regenerate the binary from migrations rather than committing the database file.
FAQ
Q: Can I use a visual merge tool like Kaleidoscope for binaries?
A: Only if the tool understands the format. Kaleidoscope handles images and PDFs; for arbitrary binaries, it falls back to a “pick one side” UI. Configure it with git config merge.tool kaleidoscope and it will launch for each binary conflict.
Q: After git checkout --ours, the file still shows as conflicted in git status. Why?
A: You need to git add the file after checking out a version. The checkout just writes bytes to disk; git add tells Git the conflict is resolved.
Q: Is there a way to auto-resolve all binary conflicts to “ours” without interactive steps?
A: Yes. Add *.png merge=ours to .gitattributes, then run git config merge.ours.driver true. Git will silently keep the current branch’s version for any matching binary during future merges.
Q: We accidentally committed a 150 MB binary and now every clone is slow. How do we fix history?
A: See the article on Large File in History Blocks the Push for a step-by-step git filter-repo walkthrough.