Stop Diffing Text, Start Diffing Logic.
Note
Diffmantic is under active development and not yet ready for public use. We're getting closer to a public release, but features and internals are still shifting quickly.
Line-based diffs like git diff break down when you refactor code. Move a function down 50 lines, and git shows it as a full Delete and re-add. Rename a parameter, and entire lines light up red and green.
Now with AI tools generating massive PRs with Moved functions and renamed symbols everywhere, the actual Change gets buried in noise. So human reviewers end up just giving in.
diffmantic fixes this by parsing your code into ASTs using Tree-sitter. It tracks structural shifts, so it knows when a function was Moved instead of deleted, and shows exact inline node edits instead of lighting up entire lines.
It works as a standalone CLI, a drop-in for git diff, or a backend for editor plugins via JSON output.
- Move Detection. When you move a function or a block, diffmantic tracks it as a Move. Not a delete + re-add. Moved functions, blocks, and statements are all first-class, with distinct colors for swapped or concurrent moves.
- Update & Rename Detection. Shows exactly what changed inside a syntax node. A variable rename, a string literal swap, a type change, you see the precise edit, not a wall of red and green.
- Side-by-Side & Inline Views. Fast side-by-side view by default, streaming directly through your pager. Uses full-width hybrid hunks for pure additions and deletions so you never get stuck in cramped columns. Also supports standard inline view (
-f inline), line wrapping (--wrap), andgit applypatches (-p). - Directory Diffing. Run
diffm dir_a dir_bto diff entire directory trees recursively, streaming changed files through a single pager session. - Git Integration. Run
diffmin any Git repo to stream a pager-backed diff of unstaged changes, staged changes with--cached, or any two revisions. - JSON Output. Stable schema with AST actions, line alignment, and character-level highlight spans. Includes selective
--uiand--fullmodes for editor plugins and frontends. - 10 Core Languages. Go, Java, JavaScript, TypeScript, TSX, Python, Rust, Zig, C, C++, Lua. Full AST normalization and matching rules powered by Tree-sitter.
- Line Diff Fallback. For unsupported file types or plain text files, Diffmantic automatically falls back to line-based diffing so you can diff any file.
| Language | Extensions |
|---|---|
| Go | .go |
| Java | .java |
| JavaScript | .js .jsx .mjs .cjs |
| TypeScript / TSX | .ts .tsx .mts .cts |
| Python | .py |
| Rust | .rs |
| Zig | .zig |
| C | .c .h |
| C++ | .cpp .cc .cxx .hpp .hh |
| Lua | .lua |
Note: Fully supported languages include tailored AST normalization (stripping punctuation noise and flattening comment/string blocks). Unrecognized languages fall back to line diffing.
curl -fsSL https://raw.githubusercontent.com/HarshK97/diffmantic/main/install.sh | shThis installs the diffm binary to ~/.local/bin. Make sure it's in your $PATH.
It auto-detects your OS and architecture, grabs the right binary from GitHub Releases, and verifies the SHA256 checksum.
# Install to a specific directory
curl -fsSL https://raw.githubusercontent.com/HarshK97/diffmantic/main/install.sh | sh -s -- --dir=/usr/local/bin
# Install a specific version
curl -fsSL https://raw.githubusercontent.com/HarshK97/diffmantic/main/install.sh | sh -s -- --version=v0.11.0brew install HarshK97/tap/diffmanticPrebuilt binaries for Linux, macOS, and Windows (amd64 + arm64) are on the Releases page.
Requires Go 1.26+ and a C compiler for the native Tree-sitter bridge.
git clone https://github.com/HarshK97/diffmantic.git
cd diffmantic
# Build binary
make build
# Install binary and man pages (defaults to ~/.local)
make install
# Or install directly with Go:
go install github.com/HarshK97/diffmantic/cmd/diffm@latestFull documentation is available via Unix manual pages:
man diffm
# or
man diffmantic# Show unstaged changes in any Git repository
diffm
# Show only staged changes
diffm --cached# Diff working tree against HEAD
diffm HEAD
# Diff between two commits, tags, or branches
diffm HEAD~1 HEAD
diffm main...feature-branch# Diff two directories recursively with pager
diffm dir-a/ dir-b/# Side-by-side diff with pager (default when a terminal is attached)
diffm before.go after.go
# Inline diff with pager
diffm before.go after.go -f inline
# Wrap long lines to terminal width in inline mode
diffm before.go after.go -f inline --wrap
# Force strict 50/50 side-by-side columns (disables hybrid full-width expansion)
diffm before.go after.go --force-sbs
# Standard patch suitable for git apply
diffm before.go after.go -p
# JSON output for editor plugins and automation
diffm before.go after.go -f json
# Fast UI mode (line alignment and highlight spans without action tree)
diffm before.go after.go -f json --ui
# Full envelope (actions, line alignment, and highlight spans)
diffm before.go after.go -f json --full
# Human-readable action list
diffm before.go after.go -f actionsdiffmantic can be configured via environment variables. Command-line flags always take precedence over environment variables.
| Variable | Default | Description |
|---|---|---|
DIFFM_FORMAT |
side-by-side |
Default diff output format (side-by-side, inline, json, actions) |
DIFFM_TAB_WIDTH |
4 |
Number of spaces per tab stop |
DIFFM_IGNORE_COMMENTS |
0 |
Ignore comments during AST diffing (1, true, yes) |
DIFFM_PARSE_ERROR_LIMIT |
0 |
Maximum parse errors permitted before falling back to line diffing |
DIFFM_SIZE_LIMIT |
1024 |
Maximum file size in KB for AST parsing before fallback (0 to disable) |
DIFFM_LINE_LIMIT |
10000 |
Maximum line count for AST parsing before fallback (0 to disable) |
DIFFM_NO_PAGER |
Unset | If set to any non-empty value, disables the interactive terminal pager |
diffmantic matches ASTs in four phases, combining the GumTree algorithm, Zhang-Shasha tree edit distance, and Chawathe edit script generation:
- Top-Down Matching. We look for identical subtrees by height. When we find an exact match, all nodes in the subtree get mapped together.
- Bottom-Up Matching. For unmatched nodes, we look for counterparts of the same type that share already-matched children. If the Dice similarity score is high enough, we match them.
- Recovery. Inside matched containers, we run LCS alignment on unmatched children (first by label, then by structural shape). For small subtrees, Zhang-Shasha (1989) tree edit distance is used as a precise fallback.
- Action Generation & Post-Processing. We produce a raw edit script (insert, delete, update, move) using Chawathe et al. (1996) edit script generation and then refine it. Child edits get collapsed into clean subtree operations, comment changes get normalized, and related moves get grouped.
diffmantic.nvim is the Neovim plugin that started this whole project. It currently ships with its own embedded alpha engine and is being migrated to use the diffm CLI as its backend via JSON output.
Planned. The JSON output is built to support editor integration, so if you want to build one, the plumbing is there.
diffm -f json outputs a stable v1 schema with child-index paths. Take a look at diffm file-a file-b -f json to see the full structure.
MIT. See LICENSE.
The engine is based on foundational research in AST differencing, tree edit distance, and edit script generation:
- GumTree: A Complete Approach for AST Differencing, Falleri et al.
- Beyond GumTree, Huvier et al.
- Simple Fast Algorithms for the Editing Distance Between Trees and Related Problems, Kaizhong Zhang and Dennis Shasha (SIAM Journal on Computing, 1989).
- Change Detection in Hierarchically Structured Information, Sudarshan S. Chawathe, Anand Rajaraman, Hector Garcia-Molina, and Jennifer Widom (ACM SIGMOD, 1996).
- GumTree GitHub Repository
