{"id":48748403,"url":"https://github.com/ilyasturki/dircmp","last_synced_at":"2026-04-15T01:00:59.796Z","repository":{"id":347860949,"uuid":"1180915465","full_name":"ilyasturki/dircmp","owner":"ilyasturki","description":"Terminal TUI for comparing two directories side by side","archived":false,"fork":false,"pushed_at":"2026-04-14T16:04:09.000Z","size":2935,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-14T17:25:50.904Z","etag":null,"topics":["cli","diff","directory-compare","directory-diff","file-comparison","ink","terminal","tui","typescript","vim-keybindings"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ilyasturki.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-13T14:49:15.000Z","updated_at":"2026-04-14T16:04:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ilyasturki/dircmp","commit_stats":null,"previous_names":["ilyasturki/dircmp"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/ilyasturki/dircmp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilyasturki%2Fdircmp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilyasturki%2Fdircmp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilyasturki%2Fdircmp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilyasturki%2Fdircmp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ilyasturki","download_url":"https://codeload.github.com/ilyasturki/dircmp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilyasturki%2Fdircmp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31821685,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T18:05:02.291Z","status":"ssl_error","status_checked_at":"2026-04-14T18:05:01.765Z","response_time":153,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","diff","directory-compare","directory-diff","file-comparison","ink","terminal","tui","typescript","vim-keybindings"],"created_at":"2026-04-12T14:07:04.542Z","updated_at":"2026-04-15T01:00:59.767Z","avatar_url":"https://github.com/ilyasturki.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dircmp\n\nTerminal TUI for comparing two directories side by side.\n\n![dircmp screenshot](assets/screenshot.png)\n\n[![npm version](https://img.shields.io/npm/v/@ilyasturki/dircmp)](https://www.npmjs.com/package/@ilyasturki/dircmp)\n[![CI](https://github.com/ilyasturki/dircmp/actions/workflows/ci.yml/badge.svg)](https://github.com/ilyasturki/dircmp/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/github/license/ilyasturki/dircmp)](LICENSE)\n[![AUR version](https://img.shields.io/aur/version/dircmp)](https://aur.archlinux.org/packages/dircmp)\n[![platform](https://img.shields.io/badge/platform-linux%20%7C%20macOS%20%7C%20windows-blue)](https://github.com/ilyasturki/dircmp/releases)\n\n## Features\n\n- **Side-by-side tree view** with color-coded diff status\n- **Built-in unified diff viewer** with line-level added/removed counts\n- **Copy, delete, and sync** entries between directories\n- **Gitignore-style ignore patterns** (global and per-directory-pair)\n- **Remote directory support** via rclone (SFTP, S3, GCS)\n- **Manual directory pairing** for renamed directories\n- **Content-based comparison** via SHA-256 hashing\n- **Sortable entries** by name, size, date modified, or status\n- **Configurable** preferences, keybindings, and external diff command\n\n## Installation\n\n### npx (no install)\n\n```sh\nnpx @ilyasturki/dircmp \u003cleft-dir\u003e \u003cright-dir\u003e\n```\n\n### npm\n\n```sh\nnpm install -g @ilyasturki/dircmp\n```\n\n### Homebrew\n\n```sh\nbrew install ilyasturki/dircmp/dircmp\n```\n\n### Arch Linux (AUR)\n\n```sh\nyay -S dircmp\n```\n\n### Nix\n\n```sh\nnix run github:ilyasturki/dircmp -- \u003cleft-dir\u003e \u003cright-dir\u003e\n```\n\nOr add to your flake inputs and install the package:\n\n```nix\n{\n  inputs.dircmp.url = \"github:ilyasturki/dircmp\";\n}\n```\n\nThen add it to your installed packages:\n\n```nix\nenvironment.systemPackages = [\n  inputs.dircmp.packages.${pkgs.system}.default\n];\n```\n\n### Build from source\n\n```sh\ngit clone https://github.com/ilyasturki/dircmp.git\ncd dircmp\nbun install\nbun run build\n./dircmp \u003cleft-dir\u003e \u003cright-dir\u003e\n```\n\n## Usage\n\n```sh\ndircmp \u003cleft-dir\u003e \u003cright-dir\u003e\ndircmp \u003cleft-file\u003e \u003cright-file\u003e    # direct file-to-file diff\n```\n\n### CLI subcommands\n\n**`diff`** — print differences to stdout:\n\n```sh\ndircmp diff \u003cleft-dir\u003e \u003cright-dir\u003e\ndircmp diff \u003cleft-dir\u003e \u003cright-dir\u003e --format json\ndircmp diff \u003cleft-dir\u003e \u003cright-dir\u003e --only modified\ndircmp diff \u003cleft-dir\u003e \u003cright-dir\u003e --stat\n```\n\nFormats: `tree` (default), `flat`, `json`. Filters: `modified`, `left-only`, `right-only`.\n\n**`check`** — silent comparison for scripts and CI:\n\n```sh\ndircmp check \u003cleft-dir\u003e \u003cright-dir\u003e        # exits 0 if identical, 1 if different\ndircmp check \u003cleft-dir\u003e \u003cright-dir\u003e --stat  # print summary before exiting\n```\n\n### Remote directories\n\nRequires [rclone](https://rclone.org). Supports SFTP, S3, GCS, and named rclone remotes:\n\n```sh\ndircmp ./local-dir sftp://user@host/path\ndircmp ./local-dir s3://bucket/prefix\ndircmp ./local-dir gcs://bucket/prefix\ndircmp ./local-dir myremote:path\n```\n\n### Flags\n\n| Flag                 | Description                              |\n| -------------------- | ---------------------------------------- |\n| `--no-ignore`        | Don't apply ignore patterns              |\n| `--ignore \u003cpattern\u003e` | Add a custom ignore pattern (repeatable) |\n| `--follow-symlinks`  | Follow symbolic links as their targets   |\n| `--help`, `-h`       | Show help                                |\n| `--version`, `-v`    | Show version                             |\n\n## Keybindings\n\nAll keybindings are customizable via `~/.config/dircmp/keybindings.json` or the in-app editor (`K`).\n\n### Navigation\n\n| Key       | Action              |\n| --------- | ------------------- |\n| `j` / `↓` | Move cursor down    |\n| `k` / `↑` | Move cursor up      |\n| `G`       | Jump to last entry  |\n| `gg`      | Jump to first entry |\n| `Ctrl+d`  | Half page down      |\n| `Ctrl+u`  | Half page up        |\n| `Ctrl+f`  | Full page down      |\n| `Ctrl+b`  | Full page up        |\n| `Ctrl+e`  | Scroll view down    |\n| `Ctrl+y`  | Scroll view up      |\n| `Tab`/`%` | Switch panel focus  |\n| `H`       | Focus left panel    |\n| `L`       | Focus right panel   |\n\n### Tree\n\n| Key       | Action                             |\n| --------- | ---------------------------------- |\n| `l` / `→` | Expand directory or enter file     |\n| `h` / `←` | Collapse directory or go to parent |\n| `Enter`   | Open unified diff view             |\n| `zR`      | Expand all directories             |\n| `zM`      | Collapse all directories           |\n| `]c`      | Jump to next difference            |\n| `[c`      | Jump to previous difference        |\n\n### Actions\n\n| Key     | Action                          |\n| ------- | ------------------------------- |\n| `\u003e`     | Copy entry to right             |\n| `\u003c`     | Copy entry to left              |\n| `Space` | Copy focused side across        |\n| `d`     | Delete selected entry           |\n| `y`     | Yank file path to clipboard     |\n| `e`     | Open focused entry in `$EDITOR` |\n| `r`     | Refresh comparison              |\n| `u`     | Undo last action                |\n| `U`     | Redo last undone action         |\n| `S`     | Swap panels                     |\n| `s`     | Open sort options               |\n| `m`     | Mark/pair renamed directory     |\n| `M`     | Unpair directory                |\n\n### Filtering \u0026 Config\n\n| Key  | Action                    |\n| ---- | ------------------------- |\n| `/`  | Filter entries by name    |\n| `f`  | Open filter menu          |\n| `i`  | Quick-add entry to ignore |\n| `I`  | Manage ignore patterns    |\n| `zi` | Toggle ignore filtering   |\n| `,`  | Open preferences          |\n| `.`  | Open actions menu         |\n| `K`  | Open keybindings editor   |\n| `?`  | Show all keybindings      |\n| `q`  | Quit                      |\n\n## Configuration\n\n### Preferences\n\nStored in `$XDG_CONFIG_HOME/dircmp/config.json` (defaults to `~/.config/dircmp/config.json`):\n\n```json\n{\n    \"dateLocale\": \"en-US\",\n    \"showHints\": true,\n    \"compareDates\": true,\n    \"compareContents\": true,\n    \"nerdFont\": true,\n    \"dirsFirst\": true,\n    \"diffCommand\": \"nvim -d\"\n}\n```\n\n| Option            | Description                                      |\n| ----------------- | ------------------------------------------------ |\n| `dateLocale`      | Locale for date formatting                       |\n| `showHints`       | Show keyboard hints in the status bar            |\n| `compareDates`    | Include modification dates in file comparison    |\n| `compareContents` | Hash file contents (SHA-256) to detect changes   |\n| `nerdFont`        | Use Nerd Font icons (falls back to ASCII)        |\n| `dirsFirst`       | List directories before files                    |\n| `diffCommand`     | External diff command (e.g., `nvim -d`, `delta`) |\n\n### Ignore patterns\n\nPatterns use gitignore syntax and are stored under `$XDG_DATA_HOME/dircmp/` (defaults to `~/.local/share/dircmp/`):\n\n- **Global:** `ignore`\n- **Per directory pair:** `pairs/\u003chash\u003e.ignore`\n\nDefault ignored: `.git`, `node_modules`, `.DS_Store`.\n\n## Manual directory pairing\n\nWhen 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.\n\n1. Navigate to the directory on one side and press `m` — a magenta `[m]` indicator appears next to the name.\n2. Switch to the other panel (`Tab`) and navigate to the corresponding renamed directory.\n3. Press `m` again — the pairing is created and the two directories are compared as one entry.\n\nBoth 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.\n\n## Color coding\n\n| Color  | Meaning                    |\n| ------ | -------------------------- |\n| Yellow | Modified (content differs) |\n| Green  | Only exists on one side    |\n| Red    | Missing from this side     |\n| Dim    | Identical                  |\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filyasturki%2Fdircmp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Filyasturki%2Fdircmp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filyasturki%2Fdircmp/lists"}