Skip to main content

git-didi

git-didi

Compare diffs between two git ranges - a "diff of diffs" tool.

Demo Branches: See test scenarios for examples you can try. Test scenario 01 is live in this repo!

This tool is particularly useful for verifying rebases and merges, especially when complex conflict resolution was involved. It helps ensure that the actual changes in your branch remain approximately the same before and after rebasing onto a new upstream.

Installation

pip install git-didi

Or with uv:

uv tool install git-didi

Usage

Common use case - checking a rebase

After fetching and rebasing your branch onto main:

git fetch
git rebase main

You can verify the rebase preserved your changes:

git-didi patch main@{1}..branch@{1} main..branch

This compares:

  • Left side: Your changes before the rebase (main@{1}..branch@{1})
  • Right side: Your changes after the rebase (main..branch)

The @{1} syntax refers to the previous position in the reflog. If both refs moved exactly once during the rebase, @{1} will work. If you've done multiple operations, you may need @{2}, @{3}, etc. Use git reflog to find the right positions.

Commands

stat - Compare diff stats

Compare git diff --stat output between two refspecs:

git-didi stat main..feature upstream/main..feature

Shows only the files where the diff statistics differ.

patch - Compare patches file-by-file

Compare patches between two refspecs, showing differences for each file:

git-didi patch main..feature upstream/main..feature

This shows a "diff of diffs" with sophisticated coloring to distinguish:

  • Changes in the outer diff (what changed between the two versions)
  • Changes in the inner diffs (the actual patches)

Options:

  • -U N / --unified N: Set context lines (default: 3)
  • -q / --quiet: Only list files with differences
  • -w / --ignore-whitespace: Ignore whitespace changes
  • -M[n] / --find-renames[=n]: Detect renames
  • -C[n] / --find-copies[=n]: Detect copies
  • --color {auto,always,never}: Control colored output
  • --pager {auto,always,never}: Control pager usage

commits - Compare commits

Compare individual commits between two refspecs:

git-didi commits main..feature upstream/main..feature

First verifies that commits correspond (same count and messages), then shows per-commit differences.

swatches - Display color palette

Show color swatches demonstrating the diff-of-diffs coloring scheme:

git-didi swatches --color=always

Filtering by path

All commands support filtering to specific paths:

git-didi patch main..feature upstream/main..feature -- src/
git-didi stat main..feature upstream/main..feature -- "*.py"

Git Aliases

You can add these to your ~/.gitconfig for convenient access:

[alias]
    didi = !git-didi
    gdds = !git-didi stat
    gddp = !git-didi patch
    gddc = !git-didi commits

Then use:

git didi patch main@{1}..branch@{1} main..branch
git gddp main..feature upstream/main..feature

How it works

The tool automatically filters out spurious differences like git index SHAs that change even when the actual patch content is identical. This makes it easy to verify that a rebase or cherry-pick truly preserved your changes without introducing unexpected modifications.

When comparing patches, it uses a sophisticated 256-color palette to make nested diffs easy to read:

  • Bright backgrounds for added/removed lines within the outer diff
  • Dark backgrounds for context lines
  • Mixed colors for lines that changed type (+ to - or vice versa)

Try it yourself - Test Scenarios

This repo includes test branches demonstrating various rebase/merge scenarios. Try:

# Clone this repo
git clone https://github.com/ryan-williams/git-didi.git
cd git-didi

# Example: Clean rebase with disjoint changes
# Alice adds priority field, Bob adds JSON format - no conflicts!
git-didi patch tests/01-clean-disjoint/base..tests/01-clean-disjoint/alice \
               tests/01-clean-disjoint/bob..tests/01-clean-disjoint/alice-rebased-on-bob
# Output: "No differences in patches" ✓

# See what each developer changed
git log --oneline tests/01-clean-disjoint/base..tests/01-clean-disjoint/alice
git log --oneline tests/01-clean-disjoint/base..tests/01-clean-disjoint/bob

# Try the other direction
git-didi patch tests/01-clean-disjoint/base..tests/01-clean-disjoint/bob \
               tests/01-clean-disjoint/alice..tests/01-clean-disjoint/bob-rebased-on-alice

# Or verify a merge commit preserved both changes
git-didi patch tests/01-clean-disjoint/base..tests/01-clean-disjoint/alice \
               tests/01-clean-disjoint/merged^1..tests/01-clean-disjoint/merged

See Test Strategy for details on the test scenarios and how to generate more.

Development

# Clone and setup
git clone https://github.com/ryan-williams/git-didi.git
cd git-didi

# Setup with uv
uv sync --extra test

# Run tests
pytest tests/ -v

# Generate additional test scenarios
./scripts/generate-test-scenario.py 01-clean-disjoint

# Install locally
uv pip install -e .

License

MIT License - see LICENSE for details.

Metadata

Release files for git-didi 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for git-didi 0.1.1
File Size Uploaded
git_didi-0.1.1.tar.gz 16.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for git-didi 0.1.1
File Interpreter ABI Platform
git_didi-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 32.4 kB

Release files / git_didi-0.1.1.tar.gz

Download URL git_didi-0.1.1.tar.gz
Size 16.6 kB
Tags Source
SHA-256 checksum
How to use checksums
7bf948f17204a5b526abf447161160f70907c6e7712d249e40dc97a70082af02
BLAKE2b-256 checksum
How to use checksums
9765d299d197233d493223d1a4f9566442ae9f4eefde4d440467741745704d25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2025.

Transparency log

Release files / git_didi-0.1.1-py3-none-any.whl

Download URL git_didi-0.1.1-py3-none-any.whl
Size 15.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a08128e0493e08bee55aa2e8052b68aaae03926bebd1498115c46178e8d09873
BLAKE2b-256 checksum
How to use checksums
d643d38be6ab71ca586ad0389d37910fdc0c6138184485dd68c604a9a8ef3205
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page