difftastic
difftastic(명령어: difft)은 줄 단위 텍스트가 아닌 구문 트리를 기반으로 파일을 비교하는 구조적 diff 도구입니다. Rust로 작성되었으며, 코드 이동, 변수 이름 변경 및 재포맷된 블록과 같은 의미 있는 변경 사항을 보여주기 위해 50개 이상의 프로그래밍 언어 문법을 이해합니다.
설치
# Using cargo (Rust)
cargo install difftastic
# macOS
brew install difftastic
# Ubuntu/Debian
sudo apt-get install difftastic
# Or download from releases
curl -sSfL https://github.com/Wilfred/difftastic/releases/latest/download/difft-x86_64-unknown-linux-gnu.tar.gz | \
tar xz -C /usr/local/bin/
# Arch Linux
sudo pacman -S difftastic
# Nix
nix-env -i difftastic
# Verify installation
difft --version
Basic Usage
# Compare two files
difft old_file.py new_file.py
# Compare two directories
difft old_dir/ new_dir/
# Read from stdin (use - for stdin)
echo "fn main() {}" | difft - new_file.rs
Git Integration
Configure as Git Difftool
# Set difftastic as the default git difftool
git config --global diff.tool difftastic
git config --global difftool.difftastic.cmd 'difft "$LOCAL" "$REMOTE"'
git config --global difftool.prompt false
# Use with git difftool
git difftool # Compare working tree vs staged
git difftool HEAD # Compare working tree vs HEAD
git difftool HEAD~1 # Compare HEAD vs HEAD~1
git difftool main..feature # Compare branches
Configure as Default Git Diff
# Set difftastic as the default diff driver via GIT_EXTERNAL_DIFF
# Add to your shell profile (~/.bashrc, ~/.zshrc):
export GIT_EXTERNAL_DIFF=difft
# Now all git diff commands use difftastic
git diff
git diff HEAD~1
git diff main..feature
git log -p # Show patches with difftastic
git show # Show commit with difftastic
.gitconfig Setup
# Add to ~/.gitconfig
[diff]
tool = difftastic
[difftool]
prompt = false
[difftool "difftastic"]
cmd = difft "$LOCAL" "$REMOTE"
# Optional: create alias for convenience
[alias]
dft = difftool
dlog = "!f() { GIT_EXTERNAL_DIFF=difft git log -p --ext-diff $@; }; f"
dshow = "!f() { GIT_EXTERNAL_DIFF=difft git show --ext-diff $@; }; f"
# Use the aliases
git dft # Structural diff
git dlog # Log with structural diffs
git dlog -5 # Last 5 commits with structural diffs
git dshow HEAD # Show latest commit with structural diff
git dshow abc123 # Show specific commit
Supported Languages
difftastic supports 50+ languages including:
Bash C C++ C#
Clojure CMake CSS Dart
Elixir Elm Erlang Go
Haskell HCL HTML Java
JavaScript JSON Julia Kotlin
LaTeX Lua Make Nix
OCaml Perl PHP Python
R Ruby Rust Scala
SQL Swift TOML TypeScript
YAML Zig and more...
# Check if a language is supported
difft --list-languages
# difftastic auto-detects language from file extension
# Falls back to text-based diff for unsupported languages
Display Modes
Side-by-Side (Default)
# Side-by-side display (default)
difft --display side-by-side old.py new.py
# Or equivalently
difft old.py new.py
Inline
# Inline display (shows changes in sequence, like unified diff)
difft --display inline old.py new.py
# Useful for narrow terminals or piping
difft --display inline old.py new.py | less
Side-by-Side Only
# Side-by-side with no syntax highlighting for unchanged parts
difft --display side-by-side-show-both old.py new.py
Color Output
# Color output (enabled by default for terminals)
difft old.py new.py
# Force color output (for piping)
difft --color always old.py new.py
# Disable color
difft --color never old.py new.py
# Color when piped to less
difft --color always old.py new.py | less -R
Width Control
# Set display width (default: terminal width)
difft --width 120 old.py new.py
# Narrow display for small terminals
difft --width 80 old.py new.py
# Wide display for large monitors
difft --width 200 old.py new.py
# Tab width (default: 4)
difft --tab-width 2 old.py new.py
Context Lines
# Set number of context lines around changes (default: 3)
difft --context 5 old.py new.py
# Minimal context
difft --context 0 old.py new.py
# More context
difft --context 10 old.py new.py
Language Override
# Force a specific language parser
difft --language python old.txt new.txt
# Useful when file extension doesn't match content
difft --language javascript config.txt config_new.txt
# Use text-based diff (disable structural parsing)
difft --language text old.py new.py
Handling Large Diffs
# Set byte limit for files (skip very large files)
difft --byte-limit 1000000 old_file new_file
# Set graph limit (controls structural diff accuracy vs speed)
difft --graph-limit 500000 old_file new_file
# For very large files, fall back to text diff
difft --language text large_old.json large_new.json
Practical Examples
# Compare before/after refactoring
difft src/old_module.py src/new_module.py
# Review a specific commit structurally
GIT_EXTERNAL_DIFF=difft git show abc123
# Compare branches
GIT_EXTERNAL_DIFF=difft git diff main..feature -- "*.py"
# Compare config file changes
difft /etc/nginx/nginx.conf /etc/nginx/nginx.conf.new
# Check formatting-only changes (structural diff ignores whitespace)
# Reformat a file and diff - only real changes shown
black old.py # Format with black
difft old.py.bak old.py # Shows no diff if only formatting changed
# Compare JSON structures
difft config_v1.json config_v2.json
Why Structural Diff
Benefits over traditional line-based diff:
1. Ignores formatting changes
- Reformatted code shows no diff if logic unchanged
- Whitespace-only changes are hidden
2. Understands code structure
- Moved functions are shown as moves, not delete+add
- Renamed variables shown inline
3. Better noise reduction
- Comment changes don't obscure code changes
- Import reordering shown cleanly
4. Language-aware matching
- Matches corresponding brackets, blocks, functions
- Understands string literals vs code
Limitations:
- Slower than line-based diff for very large files
- Some languages may not be fully supported
- Graph limit may cause fallback to text diff
Environment Variables
# Set default display mode
export DFT_DISPLAY=inline
# Set default width
export DFT_WIDTH=120
# Set default color mode
export DFT_COLOR=always
# Set default context lines
export DFT_CONTEXT=5
# Set default tab width
export DFT_TAB_WIDTH=4
# Set byte limit
export DFT_BYTE_LIMIT=1000000
# Set graph limit
export DFT_GRAPH_LIMIT=500000