https://github.com/ilyasturki/dircmp
Terminal TUI for comparing two directories side by side
https://github.com/ilyasturki/dircmp
cli diff directory-compare directory-diff file-comparison ink terminal tui typescript vim-keybindings
Last synced: about 2 months ago
JSON representation
Terminal TUI for comparing two directories side by side
- Host: GitHub
- URL: https://github.com/ilyasturki/dircmp
- Owner: ilyasturki
- License: mit
- Created: 2026-03-13T14:49:15.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-14T16:04:09.000Z (about 2 months ago)
- Last Synced: 2026-04-14T17:25:50.904Z (about 2 months ago)
- Topics: cli, diff, directory-compare, directory-diff, file-comparison, ink, terminal, tui, typescript, vim-keybindings
- Language: TypeScript
- Homepage:
- Size: 2.8 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# dircmp
Terminal TUI for comparing two directories side by side.

[](https://www.npmjs.com/package/@ilyasturki/dircmp)
[](https://github.com/ilyasturki/dircmp/actions/workflows/ci.yml)
[](LICENSE)
[](https://aur.archlinux.org/packages/dircmp)
[](https://github.com/ilyasturki/dircmp/releases)
## Features
- **Side-by-side tree view** with color-coded diff status
- **Built-in unified diff viewer** with line-level added/removed counts
- **Copy, delete, and sync** entries between directories
- **Gitignore-style ignore patterns** (global and per-directory-pair)
- **Remote directory support** via rclone (SFTP, S3, GCS)
- **Manual directory pairing** for renamed directories
- **Content-based comparison** via SHA-256 hashing
- **Sortable entries** by name, size, date modified, or status
- **Configurable** preferences, keybindings, and external diff command
## Installation
### npx (no install)
```sh
npx @ilyasturki/dircmp
```
### npm
```sh
npm install -g @ilyasturki/dircmp
```
### Homebrew
```sh
brew install ilyasturki/dircmp/dircmp
```
### Arch Linux (AUR)
```sh
yay -S dircmp
```
### Nix
```sh
nix run github:ilyasturki/dircmp --
```
Or add to your flake inputs and install the package:
```nix
{
inputs.dircmp.url = "github:ilyasturki/dircmp";
}
```
Then add it to your installed packages:
```nix
environment.systemPackages = [
inputs.dircmp.packages.${pkgs.system}.default
];
```
### Build from source
```sh
git clone https://github.com/ilyasturki/dircmp.git
cd dircmp
bun install
bun run build
./dircmp
```
## Usage
```sh
dircmp
dircmp # direct file-to-file diff
```
### CLI subcommands
**`diff`** — print differences to stdout:
```sh
dircmp diff
dircmp diff --format json
dircmp diff --only modified
dircmp diff --stat
```
Formats: `tree` (default), `flat`, `json`. Filters: `modified`, `left-only`, `right-only`.
**`check`** — silent comparison for scripts and CI:
```sh
dircmp check # exits 0 if identical, 1 if different
dircmp check --stat # print summary before exiting
```
### Remote directories
Requires [rclone](https://rclone.org). Supports SFTP, S3, GCS, and named rclone remotes:
```sh
dircmp ./local-dir sftp://user@host/path
dircmp ./local-dir s3://bucket/prefix
dircmp ./local-dir gcs://bucket/prefix
dircmp ./local-dir myremote:path
```
### Flags
| Flag | Description |
| -------------------- | ---------------------------------------- |
| `--no-ignore` | Don't apply ignore patterns |
| `--ignore ` | Add a custom ignore pattern (repeatable) |
| `--follow-symlinks` | Follow symbolic links as their targets |
| `--help`, `-h` | Show help |
| `--version`, `-v` | Show version |
## Keybindings
All keybindings are customizable via `~/.config/dircmp/keybindings.json` or the in-app editor (`K`).
### Navigation
| Key | Action |
| --------- | ------------------- |
| `j` / `↓` | Move cursor down |
| `k` / `↑` | Move cursor up |
| `G` | Jump to last entry |
| `gg` | Jump to first entry |
| `Ctrl+d` | Half page down |
| `Ctrl+u` | Half page up |
| `Ctrl+f` | Full page down |
| `Ctrl+b` | Full page up |
| `Ctrl+e` | Scroll view down |
| `Ctrl+y` | Scroll view up |
| `Tab`/`%` | Switch panel focus |
| `H` | Focus left panel |
| `L` | Focus right panel |
### Tree
| Key | Action |
| --------- | ---------------------------------- |
| `l` / `→` | Expand directory or enter file |
| `h` / `←` | Collapse directory or go to parent |
| `Enter` | Open unified diff view |
| `zR` | Expand all directories |
| `zM` | Collapse all directories |
| `]c` | Jump to next difference |
| `[c` | Jump to previous difference |
### Actions
| Key | Action |
| ------- | ------------------------------- |
| `>` | Copy entry to right |
| `<` | Copy entry to left |
| `Space` | Copy focused side across |
| `d` | Delete selected entry |
| `y` | Yank file path to clipboard |
| `e` | Open focused entry in `$EDITOR` |
| `r` | Refresh comparison |
| `u` | Undo last action |
| `U` | Redo last undone action |
| `S` | Swap panels |
| `s` | Open sort options |
| `m` | Mark/pair renamed directory |
| `M` | Unpair directory |
### Filtering & Config
| Key | Action |
| ---- | ------------------------- |
| `/` | Filter entries by name |
| `f` | Open filter menu |
| `i` | Quick-add entry to ignore |
| `I` | Manage ignore patterns |
| `zi` | Toggle ignore filtering |
| `,` | Open preferences |
| `.` | Open actions menu |
| `K` | Open keybindings editor |
| `?` | Show all keybindings |
| `q` | Quit |
## Configuration
### Preferences
Stored in `$XDG_CONFIG_HOME/dircmp/config.json` (defaults to `~/.config/dircmp/config.json`):
```json
{
"dateLocale": "en-US",
"showHints": true,
"compareDates": true,
"compareContents": true,
"nerdFont": true,
"dirsFirst": true,
"diffCommand": "nvim -d"
}
```
| Option | Description |
| ----------------- | ------------------------------------------------ |
| `dateLocale` | Locale for date formatting |
| `showHints` | Show keyboard hints in the status bar |
| `compareDates` | Include modification dates in file comparison |
| `compareContents` | Hash file contents (SHA-256) to detect changes |
| `nerdFont` | Use Nerd Font icons (falls back to ASCII) |
| `dirsFirst` | List directories before files |
| `diffCommand` | External diff command (e.g., `nvim -d`, `delta`) |
### Ignore patterns
Patterns use gitignore syntax and are stored under `$XDG_DATA_HOME/dircmp/` (defaults to `~/.local/share/dircmp/`):
- **Global:** `ignore`
- **Per directory pair:** `pairs/.ignore`
Default ignored: `.git`, `node_modules`, `.DS_Store`.
## Manual directory pairing
When a directory has been renamed on one side, it shows up as two unmatched entries (one left-only, one right-only) instead of being compared together. Manual pairing lets you tell dircmp that two differently-named directories are logically the same, so their contents are diffed against each other.
1. Navigate to the directory on one side and press `m` — a magenta `[m]` indicator appears next to the name.
2. Switch to the other panel (`Tab`) and navigate to the corresponding renamed directory.
3. Press `m` again — the pairing is created and the two directories are compared as one entry.
Both directories must share the same parent directory. To cancel a pending mark before pairing, press `m` on the marked directory, `M`, or `Escape`. To remove an existing pairing, press `M` on the paired entry or restart the app.
## Color coding
| Color | Meaning |
| ------ | -------------------------- |
| Yellow | Modified (content differs) |
| Green | Only exists on one side |
| Red | Missing from this side |
| Dim | Identical |
## License
[MIT](LICENSE)