DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Git Branch Comparison — A Senior Dev’s Playbook (Concise Expert)

Git Branch Comparison — A Senior Dev’s Playbook (Concise → Expert)

TL;DR — Use A...B for “what actually differs since the common ancestor”, A..B for “what’s in B that isn’t in A”. Start with ahead/behind counts and a stat diff, then drill into commit graphs, rename‑aware diffs, and range‑diff for rebases.


Table of Contents

  1. Quick Answers (copy/paste)
  2. Double vs Triple Dots (mental model)
  3. File & Content Diffs That Read Well
  4. Commit‑Level Analysis (surgical view)
  5. What Will Actually Merge? (merge‑base)
  6. Triage & Impact (where the churn lives)
  7. Review‑Ready Workflows (pre‑PR / dry‑run)
  8. Windows / PowerShell Equivalents
  9. Pro Aliases (drop‑in)
  10. Decision Cheatsheet

Quick Answers (copy/paste)

Replace A / B with your branches (e.g., origin/main and feature/payments).

# How far apart are they?
git rev-list --left-right --count A...B    # → <A-only> <B-only>

# High-level file summary
git diff --stat A...B

# Full content diff (triple dot: versus merge-base)
git diff A...B
Enter fullscreen mode Exit fullscreen mode

Graph + commits per side:

git log --oneline --left-right --cherry-pick --graph A...B
Enter fullscreen mode Exit fullscreen mode

Names only / status:

git diff --name-only  A...B
git diff --name-status A...B  # A/M/D/R status
Enter fullscreen mode Exit fullscreen mode

Detect renames/moves better:

git diff -M -C A...B
Enter fullscreen mode Exit fullscreen mode

Double vs Triple Dots (mental model)

Pattern Interprets As Use For
A..B commits in B not in A “What would I pull from B into A?”
A...B compare each side vs merge‑base(A,B) “What actually differs since we diverged?” (PR view)

Find the merge base explicitly:

git merge-base A B
Enter fullscreen mode Exit fullscreen mode

File & Content Diffs That Read Well

# Files changed (names only / with status)
git diff --name-only A...B
git diff --name-status A...B

# Ignore whitespace noise
git diff -w A...B

# Word-level (docs/markdown)
git diff --word-diff A...B

# Function/context aware (C/C++/Java/C#)
git diff -W A...B

# Focus a path/glob
git diff A...B -- src/api/**.cs
Enter fullscreen mode Exit fullscreen mode

Rename/move detection boosters:

git diff -M -C --stat A...B
Enter fullscreen mode Exit fullscreen mode

Commit‑Level Analysis (surgical view)

Linearized graph with sides marked:

git log --oneline --graph --decorate --left-right --cherry-pick A...B
Enter fullscreen mode Exit fullscreen mode

Which commits from B are not in A (cherry candidates):

git cherry -v A B
Enter fullscreen mode Exit fullscreen mode

Compare two series of commits (e.g., before/after rebase):

git range-diff oldA..oldB newA..newB
# common real-world: compare 'topic' before/after rebase onto 'main'
git range-diff origin/main..feature v2/main..feature
Enter fullscreen mode Exit fullscreen mode

What Will Actually Merge? (merge‑base)

Preview conflicts safely:

git switch A
git merge --no-commit --no-ff B   # dry run
git merge --abort                  # back out
Enter fullscreen mode Exit fullscreen mode

Show deltas vs merge‑base:

mb=$(git merge-base A B)
git diff --stat $mb A
git diff --stat $mb B
Enter fullscreen mode Exit fullscreen mode

Triage & Impact (where the churn lives)

Top churn files in this comparison:

git diff --numstat A...B | sort -k1,1nr | head
# columns: added  removed  path
Enter fullscreen mode Exit fullscreen mode

Authorship focus for a hot file:

git blame B -- path/to/file | cut -d'(' -f2 | cut -d' ' -f1 | sort | uniq -c | sort -nr
Enter fullscreen mode Exit fullscreen mode

Extension distribution (what kind of work changed):

git diff --name-only A...B | awk -F. '{print $NF}' | sort | uniq -c | sort -nr
Enter fullscreen mode Exit fullscreen mode

Review‑Ready Workflows (pre‑PR / dry‑run)

A) What your PR actually changes

git fetch origin
git diff --stat origin/main...HEAD
git log --oneline --left-right --cherry-pick origin/main...HEAD
Enter fullscreen mode Exit fullscreen mode

B) Safety check before merging B into A

git switch A
git merge --no-commit --no-ff B
git merge --abort
Enter fullscreen mode Exit fullscreen mode

C) Cherry-pick only the good stuff

git cherry -v A B | grep '^+' | awk '{print $2}' | xargs -I{} git cherry-pick {}
Enter fullscreen mode Exit fullscreen mode

Tip: On protected branches (Azure DevOps/GitHub), prefer PRs over history edits. Use range-diff to prove your rebase didn’t change semantics.


Windows / PowerShell Equivalents

PowerShell doesn’t have xargs by default; use loops.

# Ahead/behind
git rev-list --left-right --count A...B

# Commit graph (works the same)
git log --oneline --left-right --cherry-pick --graph A...B

# Cherry-pick (+ commits from B)
$commits = git cherry -v A B | Select-String '^\+' | ForEach-Object { ($_ -split ' ')[1] }
foreach ($c in $commits) { git cherry-pick $c }
Enter fullscreen mode Exit fullscreen mode

Prefer Git Bash or WSL for the awk|xargs one‑liners:

git diff --name-only A...B | awk -F. '{print $NF}' | sort | uniq -c | sort -nr
Enter fullscreen mode Exit fullscreen mode

Pro Aliases (drop‑in)

Put these in ~/.gitconfig:

[alias]
  aheadbehind = rev-list --left-right --count
  lg = log --oneline --graph --decorate
  lga = log --oneline --graph --decorate --all
  cmp = !sh -c 'git lg --left-right --cherry-pick "$1...$2"' -
  whatmerges = !sh -c 'mb=$(git merge-base "$1" "$2"); echo MERGE-BASE:$mb; git diff --stat $mb "$1"; echo ----; git diff --stat $mb "$2"' -
  rdiff = range-diff
Enter fullscreen mode Exit fullscreen mode

Usage:

git aheadbehind A...B
git cmp A B
git whatmerges A B
Enter fullscreen mode Exit fullscreen mode

Decision Cheatsheet

  • High‑level difference fastgit diff --stat A...B + git aheadbehind A...B
  • Exact commits differinggit log --left-right --cherry-pick A...B
  • Preview merge conflictsgit merge --no-commit --no-ff B on branch A, then --abort
  • Compare two rebases/seriesgit range-diff old..new base..topic
  • Renames/moves matter → add -M -C to git diff
  • Windows shell → prefer Git Bash/WSL for awk|xargs, or PowerShell loops

✍️ Written by: Cristian Sifuentes — Full-stack developer & AI/JS enthusiast, passionate about React, TypeScript, and scalable architectures.

Top comments (2)

Collapse
 
shemith_mohanan_6361bb8a2 profile image
shemith mohanan

This is a solid breakdown, Cristian 👏
The quick-copy “decision cheatsheet” alone is gold.
Most devs know the double vs triple-dot difference in theory, but struggle to apply it when reviewing PRs — your examples make the mental model stick instantly.
Bookmarking this as a go-to reference for code review workflows!

Collapse
 
hashbyt profile image
Hashbyt

That double vs. triple dot explanation is golden! 🌟 Using git cmp (your alias) and range-diff for pre-PR checks is absolutely the senior dev move. Excellent playbook!