codediff 0.0.7

Fast, robust, syntax-aware code diffing using tree-sitter ASTs
Documentation

CodeDiff

CI Latest release docs.rs

Fast, robust, syntax-aware code diffing.

A screenshot showing codediff diffing a Python refactoring. It correctly identifies assignment operator as changed, instead of anchoring on the text as unix diff would

Installation

cargo install codediff

This command builds CodeDiff from source. You need a C compiler on PATH and a Rust toolchain, edition 2024 or later (rustc 1.85 or later). The build compiles every tree-sitter grammar from C. The first cargo install takes a few minutes, because of this and the lto = "fat" release profile.

Pre-built binaries for Linux, macOS (Intel and Apple Silicon), and Windows are attached to every GitHub release.

The git-history analysis tools in src/bin/ sit behind an off-by-default stats feature. cargo install does not install these tools. They matter only if you build from a checkout. The stats feature exists because these tools need git2 and its own OpenSSL/libssh2 build dependencies. The diffing tool itself does not need these dependencies. Build these tools with cargo build --features stats.

Editor integration

For Neovim, see codediff.nvim.

Using CodeDiff

The interactive TUI

codediff with no arguments opens a terminal UI with two panels, "Before" and "After". Terminals 220 columns or wider show both panels side by side. Narrower terminals show one panel at a time. codediff BEFORE AFTER, with two file paths, opens directly into their diff, not an empty viewer. If you build from a checkout instead of cargo install, use cargo run -- in place of codediff in every example below.

  • Tab — switch the active panel.
  • o — open a file selector for the active panel. Once both panels have a file, codediff computes and draws the diff between them automatically, color-coded by change type (inserted, deleted, updated, moved) using the current overlay theme - see c below.
  • c — open the color theme picker. Built-in themes: Dark (default), Solarized Dark, Solarized Light, Dracula, Nord, Gruvbox Dark, Monokai, One Dark. codediff remembers your choice across runs.
  • ? — show every keybinding, plus copyright/license/repository info. j/k scrolls it. ? or Esc closes it.
  • Arrow keys or h/j/k/l — move the cursor, one line or column at a time, same as a text editor. The range under the cursor, and the matching range on the other panel, highlight in blue whenever it's part of a real change; unchanged (identical) content is never highlighted. The other panel's cursor always follows the matched node.
  • n/p — jump straight to the next or previous change. This skips unchanged lines entirely. It wraps around at the start or end of the file.
  • / — search the focused panel for text. Enter jumps to the nearest match and highlights every match in blue. Esc cancels; an empty query clears the current search's highlights. >/< step to the next/previous match once a search is active.
  • Page Up/Page Down/Home/End — scroll.
  • q or Esc — quit. If a dialog is open, Esc cancels the dialog instead.

If a diff involves two unrelated files, full structural analysis can take several seconds. codediff detects this case. It asks whether to wait for the precise, slow result or accept a faster, approximate result instead.

Headless / batch mode

codediff --headless BEFORE AFTER, or its synonym --batch, prints the diff as plain text, with optional color, instead of opening the TUI. Use this for scripts, CI, or any case where stdout is not a real terminal. Headless mode also starts automatically whenever stdout is not a terminal, for example when piped into less or redirected to a file. Because of this, codediff BEFORE AFTER | less works without the flag.

codediff collapses long runs of unchanged lines. It keeps 3 lines of context on each side of a change, the same convention as diff -u. codediff also prefixes each hunk with the nearest enclosing function, class, or struct line, when that line is not otherwise visible. This shows the location of a change deep inside a large file. The reader does not need to see the whole file around it.

By default, headless mode uses the same fast, approximate fallback that the TUI offers for unrelated-looking files, without asking. Pass --exact to force the full, precise analysis instead. Pass NO_COLOR=1 (see https://no-color.org) to disable ANSI colors, for example when you redirect output to a file.

Git integration

codediff doubles as a git difftool backend. Run the interactive setup wizard, which asks whether to configure it globally or for the current repository only:

codediff git configure

Or configure it by hand:

git config difftool.codediff.cmd 'codediff "$LOCAL" "$REMOTE"'
git difftool --tool=codediff

Run git config diff.tool codediff to make plain git difftool use codediff by default, without needing --tool. If you do not want git to ask "view diff ... [Y/n]?" before every file, run git config difftool.prompt false.

git difftool opens the interactive TUI. git diff and git log -p never do. git diff pipes its output through git's pager, and a full-screen TUI cannot draw onto a pipe, so codediff always falls back to plain text there regardless of terminal or GIT_EXTERNAL_DIFF config (see "Headless / batch mode" above). If you want the interactive viewer from git, use git difftool, not git diff. If git difftool still doesn't open interactively over SSH, reconnect with ssh -t — the session needs an allocated pseudo-terminal; tmux panes always have one, so tmux itself is never the cause.

codediff also works directly with git diff and git log -p, through GIT_EXTERNAL_DIFF. This path needs no difftool config:

GIT_EXTERNAL_DIFF=codediff git diff

Files with no tree-sitter grammar (an unrecognized extension, or none at all - Makefile, Dockerfile, ...) fall back to a plain line-level diff instead of the syntax-aware one, so a change touching one of them never blocks git diff from showing the rest.

Guiding principles

Robust

CodeDiff must process 100% of all commits in the full test dataset.

The full test dataset holds the git commit history of about 7,400 open-source git repositories, as available on the main branch. This list of repositories comes from the Gentoo Linux distribution. Find it in research/list_of_repositories.csv.

A smaller list of 100 repositories, the "small" dataset, is available in the same directory. Use it for faster iteration when you debug.

Fast

CodeDiff must produce a diff in under 400ms for 99.99% of all commits in the full test dataset.

In code, I accept less readable, more complex code, if that code is faster.

Benchmarks make sure that performance does not regress.

License

Copyright (C) 2026 Marko Ivankovic

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation.

See the LICENSE file for the full text of the License.

Cannot use AGPL software?

Contact me for options.

AI policy

This project uses substantial AI assistance, currently Claude Code. Most commits disclose this with a Co-Authored-By trailer and a link to the session that produced them. This project does not hide that fact. This project does not treat AI assistance as a lesser way to write software.

AI-assisted contributions are welcome. Use whatever tools help you do good work. Disclose your use of these tools the same way. You are still responsible for understanding and standing behind whatever you submit.

For Developers, human or otherwise

See CONTRIBUTING.md for the technology overview, code-quality and testing expectations, project structure, and what CI checks on every push and PR. AGENTS.md has additional AI-agent-specific conventions.