Skip to content

git range-diff: Quick Reference

Compare two commit ranges after a rebase, subtree pull, cherry-pick batch, or force-push. Pair commits on the old side with commits on the new side and show the patch delta between matched pairs.

Syntax

git range-diff <old-base>..<old-tip> <new-base>..<new-tip>
git range-diff <old-range> <new-range>          # implicit HEAD on new side
git range-diff A B                              # HEAD vs B

Reading the output

Symbol Meaning
1: abc123 = 2: def456 Commit is byte-identical on both sides
1: abc123 ! 2: def456 Commit exists on both sides but the patch changed
1: abc123 < -: ------ Commit removed on the new side
-: ------ > 2: def456 Commit added on the new side

A clean rebase is a wall of = lines. Anything else needs review.

Common DevOps patterns

# 1. Validate a feature-branch rebase before review
git range-diff origin/main@{pre-rebase-sha} origin/main..feature/payments

# 2. Audit a vendor subtree pull
git rev-parse HEAD > /tmp/vendor-pre.txt
git subtree pull --prefix=lib/vendor library-repo main --squash
git range-diff $(cat /tmp/vendor-pre.txt)..HEAD^2 HEAD^2..HEAD

# 3. Audit a cherry-pick batch onto release branch
git range-diff main..@{yesterday} release/2.x..release/2.x@{0}

# 4. Validate a force-pushed stacked branch
git range-diff origin/pr/42@{1} origin/pr/42

Useful flags

git range-diff --no-patch A B           # only summary lines, no patch diffs
git range-diff --creation-factor=80 A B # stricter pairing (more new commits as adds)
git range-diff --creation-factor=30 A B # looser pairing (more forced matches)
git range-diff --diff-merges=first-parent A B  # for merge-heavy ranges

Pre-merge CI gate (Forgejo Actions)

- uses: https://code.forgejo.org/actions/checkout@v4
  with:
    fetch-depth: 0
- name: range-diff gate
  run: |
    git fetch origin "${{ github.base_ref }}"
    changes=$(git range-diff --no-patch \
      origin/"${{ github.base_ref }}"..HEAD \
      origin/"${{ github.base_ref }}"..HEAD | \
      grep -E '^[<>!]' || true)
    if [[ -n "$changes" ]]; then
      echo "Range diff detected substantive changes; manual review required:"
      echo "$changes"
      exit 1
    fi

Pairing with safe force-push

# Contributor pushes with --force-with-lease so reviewers can diff against the prior SHA
git push --force-with-lease=refs/heads/pr/42:abc1234 origin pr/42

# Reviewer side: range-diff the pre-push and post-push tips
git fetch origin pr/42
git range-diff origin/pr/42@{1} origin/pr/42

Gotchas

  • Pairing uses commit message, then author time, then patch similarity. Rename a message mid-rebase and pairing breaks.
  • A split-or-merged commit shows as both a removal and an addition.
  • Range-diff compares patches, not behaviour. A patch change that's actually identical (e.g., optimiser-equal reordering) still shows !. Run tests.
  • Output can be long. Use --no-patch for the summary, | less for paging.
  • range-diff needs both sides locally. Shallow clones: git fetch --unshallow first or fetch the base branch explicitly.