A git diff pager based on delta but with a file tree, à la GitHub.
## ❤️ Sponsoring
If you enjoy `diffnav` and want to help, consider supporting the project with a
donation at the [sponsors page](https://github.com/sponsors/dlvhdr).
## Sponsors
TUI Visionary
TUI Power User
TUI Backer
## Installation
Homebrew:
```sh
brew install dlvhdr/formulae/diffnav
```
Go:
```sh
git clone https://github.com/dlvhdr/diffnav.git
cd diffnav
go install .
```
> [!NOTE]
> To get the icons to render properly you should download and install a Nerd font from https://www.nerdfonts.com/. Then, select that font as your font for the terminal.
>
> _You can install these with brew as well: `brew install --cask font--nerd-font`_
## Usage
### Pipe into `diffnav`
- `git diff | diffnav`
- `gh pr diff https://github.com/dlvhdr/gh-dash/pull/447 | diffnav`
### Set up as Global Git Diff Pager
```bash
git config --global pager.diff diffnav
```
## Flags
| Flag | Description |
| -------------------- | --------------------------------------------------------------------- |
| `--side-by-side, -s` | Force side-by-side diff view |
| `--unified, -u` | Force unified diff view |
| `--watch, -w` | Watch mode: periodically re-run a command and refresh |
| `--watch-cmd` | Command to run in watch mode (implies `--watch`, default: `git diff`) |
| `--watch-interval` | Interval between watch refreshes (default: `2s`) |
Example:
```sh
git diff | diffnav --unified
git diff | diffnav -u
```
### Watch Mode
Watch mode lets diffnav periodically re-run a diff command and refresh the display automatically. This is useful for monitoring changes as you work.
```sh
# watch unstaged changes (default: git diff, every 2s)
diffnav --watch
# watch staged changes with a custom interval
diffnav --watch-cmd "git diff --cached" --watch-interval 5s
# watch changes against a specific branch
diffnav --watch-cmd "git diff main..."
```
## Configuration
The config file is searched in this order:
1. `$DIFFNAV_CONFIG_DIR/config.yml` (if env var is set)
2. `$XDG_CONFIG_HOME/diffnav/config.yml` (if set, macOS only)
3. `~/.config/diffnav/config.yml` (macOS and Linux)
4. OS-specific config directory (e.g., `~/Library/Application Support/diffnav/config.yml` on macOS)
Example config file:
```yaml
ui:
# Hide the header to get more screen space for diffs
hideHeader: true
# Hide the footer (keybindings help)
hideFooter: true
# Start with the file tree hidden (toggle with 'e')
showFileTree: false
# Customize the file tree width (default: 26)
fileTreeWidth: 30
# Customize the search panel width (default: 50)
searchTreeWidth: 60
# Icon style: "status" (default), "simple", "filetype", "full", "unicode", or "ascii"
icons: nerd-fonts-status
# Color filenames by git status (default: true)
colorFileNames: false
# Show the amount of lines added / removed next to the file
showDiffStats: false
# Use side-by-side diff view (default: true, set false for unified)
sideBySide: true
# How many levels of folders to open on start (-1 = all, 0 = none, 1 = first level, etc.)
startFoldersOpenDepth: 1
```
| Option | Type | Default | Description |
| :------------------------- | :----- | :------------------ | :-------------------------------------------------------- |
| `ui.hideHeader` | bool | `false` | Hide the "DIFFNAV" header |
| `ui.hideFooter` | bool | `false` | Hide the footer with keybindings help |
| `ui.showFileTree` | bool | `true` | Show file tree on startup |
| `ui.fileTreeWidth` | int | `26` | Width of the file tree sidebar |
| `ui.searchTreeWidth` | int | `50` | Width of the search panel |
| `ui.icons` | string | `nerd-fonts-status` | Icon style (see below for details) |
| `ui.colorFileNames` | bool | `true` | Color filenames by git status |
| `ui.showDiffStats` | bool | `true` | Show the amount of lines added / removed next to the file |
| `ui.sideBySide` | bool | `true` | Use side-by-side diff view (false for unified) |
| `ui.startFoldersOpenDepth` | int | `-1` | Folder open depth on start (-1 = all, 0 = none) |
### Icon Styles
| Style | Description |
| :-------------------- | :--------------------------------------------------------------- |
| `nerd-fonts-status` | Boxed git status icons colored by change type |
| `nerd-fonts-simple` | Generic file icon colored by change type |
| `nerd-fonts-filetype` | File-type specific icons (language icons) colored by change type |
| `nerd-fonts-full` | Both status icon and file-type icon, all colored |
| `unicode` | Unicode symbols (+/⛌/●) |
| `ascii` | Plain ASCII characters (+/x/\*) |
### Delta
You can also configure the diff rendering through delta. Check out [their docs](https://dandavison.github.io/delta/configuration.html).
If you want the exact delta configuration I'm using - [it can be found here](https://github.com/dlvhdr/diffnav/blob/main/cfg/delta.conf).
## Keys
| Key | Description |
| :-------------------------- | :------------------------------- |
| j | Next node |
| k | Previous node |
| n | Next file |
| p / N | Previous file |
| Ctrl-d | Scroll the diff half page down |
| Ctrl-u | Scroll the diff half page up |
| Ctrl-e | Scroll the diff one line down |
| Ctrl-y | Scroll the diff one line up |
| e | Toggle the file tree |
| t | Search/go-to file |
| y | Copy file path |
| i | Cycle icon style |
| o | Open file in $EDITOR |
| s | Toggle side-by-side/unified view |
| Tab | Switch focus between the panes |
| q | Quit |
## Discord
Have questions? Join our [Discord community](https://discord.gg/SXNXp9NctV)!
## Contributing
See the contribution guide at [https://www.gh-dash.dev/contributing](https://www.gh-dash.dev/contributing/).
## Under the Hood
`diffnav` uses:
- [Bubble Tea](https://github.com/charmbracelet/bubbletea) for the TUI
- [`delta`](https://github.com/dandavison/delta) for viewing the diffed file
Screenshots use:
- [kitty](https://sw.kovidgoyal.net/kitty/) for the terminal
- [tokyonight](https://github.com/folke/tokyonight.nvim) for the color scheme
- [CommitMono](https://www.nerdfonts.com/font-downloads) for the font