See exactly what differs between two branches
How do I compare two branches in Git?
Short answer
git diff main..feature compares the two tips; git diff main...feature (three dots) compares against their common ancestor and shows only what the feature branch added. The three-dot form is almost always the one you want for reviewing a branch.
git diff main...feature --stat
Summarises only what the feature branch changed, ignoring anything main added since
Does this match your situation?
- You want to review a branch before merging it.
- You need to know which files a branch touched.
- Two branches have diverged and you want to see how.
Step-by-step fix
Understand two dots versus three
This distinction causes more confusion than any other in Git. Two dots compares the endpoints. Three dots compares the feature branch against the point it forked from — which excludes everything main gained in the meantime.
step 1git diff main..feature # every difference between the two tips git diff main...feature # only what feature added since it forkedUse three dots to review a branch. Two dots also shows main's newer commits as removals, which is rarely what you mean.
Start with a file-level summary
A stat view tells you the shape of the change before you read a single line of diff.
step 2git diff main...feature --stat git diff main...feature --name-statusList the commits each branch has
Sometimes the question is which commits differ, not which lines. The left-right form counts both directions at once.
step 3git log --oneline main..feature # commits only on feature git log --oneline feature..main # commits only on main git rev-list --left-right --count main...featureRead the full diff, or one file at a time
Narrow to a path once you know where to look, or open the whole change in a GUI.
step 4git diff main...feature -- src/app.ts git difftool -d main...featureCompare against a remote branch
Fetch first so your remote-tracking branch is current, otherwise you're comparing against a stale snapshot.
step 5git fetch origin git diff origin/main...HEAD --stat
Why this works
A branch is a pointer to a commit, and every commit reaches back through its parents, so 'the difference between two branches' is ambiguous: do you mean the difference between the two end states, or the work one branch did after they parted? Two dots answers the first, three dots the second by diffing against the merge base. Pull requests show the three-dot diff, which is why a two-dot comparison locally can look alarmingly different from what your reviewer sees.
How to stop it happening again
- Get in the habit of three dots when reviewing branch work.
- Rebase or merge main into your branch regularly so the two views converge.
- Fetch before comparing against origin/* so you're not reading a stale cache.
Commands used in this guide
git diffShow exactly what changed - between your files, the index, commits or branches.
git logBrowse commit history with as much or as little detail as you want.
git merge-baseFind the commit two branches diverged from.
git difftoolView diffs in a graphical diff viewer instead of the terminal.
git rev-listList commit hashes matching a range or filter - the engine behind git log.
Still stuck?
Search the full command reference and every other rescue guide — there are 56 of them, covering everything from detached HEAD to force-push disasters.
Browse all guides →Frequently asked questions
What's the difference between two dots and three dots in git diff?
git diff a..b compares the two commits directly. git diff a...b compares b against the common ancestor of a and b, showing only what b changed since they diverged. Three dots matches what a pull request displays.
How do I list commits that are on one branch but not another?
git log --oneline main..feature shows commits reachable from feature but not main. Reverse the order for the opposite. git rev-list --left-right --count main...feature gives both counts at once.
How do I see which files a branch changed?
git diff main...feature --name-status lists each changed file with its status letter, and --stat adds line counts. Both are far easier to scan than the full diff when you just want the shape of the change.
Related rescue guides
How do I find which commit introduced a particular piece of code?
git log -S "text" (the pickaxe) finds every commit where the number of occurrences of that string changed — which is how you locate the commit that introduced or deleted it. git log -L traces one function's entire evolution.
Read the fix →Always fixableHow do I find which commit broke my code?
git bisect binary-searches your history. Tell it one commit that works and one that doesn't; it checks out the midpoint and asks you to test, halving the range each time. With git bisect run it tests automatically and names the guilty commit unattended.
Read the fix →Always fixableGit says I have merge conflicts — how do I fix them?
Git pauses and marks the clashing sections with <<<<<<<, ======= and >>>>>>>. Edit each file to the version you actually want, delete the markers, git add the file, then git merge --continue. If it gets overwhelming, git merge --abort returns you to exactly where you started.
Read the fix →Always fixableMy push was rejected — 'Updates were rejected because the remote contains work that you do not have'. What now?
Someone pushed commits you don't have yet, so your push would erase them. Git is protecting you. Fetch and integrate their work first with git pull --rebase, then push again. Never reach for --force here unless you genuinely intend to delete what's on the server.
Read the fix →