Overview
Gitforest is a terminal UI for managing many Git repositories at once. It scans configured directories for git repos, non-git projects, and submodules; surfaces uncommitted changes and unpushed/unpulled commits at a glance; and lets me run pull, push, fetch, or gh-driven GitHub operations across one repo or a whole selection without leaving the terminal.
I built it because I work across a ~/projects folder with dozens of repos plus a dotfiles tree of submodules, and “is everything pushed?” was a question I kept answering by cd-ing through directories. Gitforest answers it on one screen.
Features
Project discovery
Configured directories are scanned with bounded depth and a concurrency limit. Gitforest recognizes git repos via .git, submodules via .gitmodules, and non-git projects via marker files (package.json, Cargo.toml, pyproject.toml, go.mod, Gemfile, pom.xml, build.gradle, and others) so I can spot folders that should probably be repos but aren’t yet.
Status dashboard
For every git repo, the list shows:
- Clean / dirty working tree
- Number of unpushed and unpulled commits relative to the upstream
- Submodule indicator
- Last activity timestamp for sorting
Sort by name, status, or last activity; filter with / and a free-text query.
Batch git operations
Multi-select with space (or a to select all), then run an operation across the whole selection:
ppush,Ppull,ffetchiinitialize git in selected non-git projectsccreate a GitHub repo for selected directories (default visibility configurable)Aarchive a GitHub repo
Push and pull are parallelized with backpressure; results stream back into the dashboard as they finish.
Background sync
A worker fetches remotes every five minutes so the unpushed/unpulled counters stay roughly current without me hammering f myself.
Caching
A local SQLite database (via Drizzle) caches the last scan result, so subsequent runs render instantly and only re-stat the directories that changed.
Configuration
~/.config/gitforest/config.yaml controls which directories to scan and how:
directories:
- path: ~/projects
maxDepth: 2
label: Projects
- path: ~/.dotfiles
maxDepth: 3
label: Dotfiles
scan:
ignore: [node_modules, .git, vendor]
concurrency: 5
github:
defaultVisibility: private
display:
sortBy: status
sortDirection: descgitforest --init writes a starter file the first time.
Quick start
# Run without installing
bunx gitforest --init
bunx gitforest
# Or install globally
bun add -g gitforest
gitforestTechnology stack
- TypeScript on the Bun runtime, distributed on npm as
gitforest - Ink for the terminal UI. React is rendered into a TTY
@inkjs/uiandink-select-inputfor higher-level componentsBun.$for git shell operations, theghCLI for GitHub operations- Drizzle ORM over SQLite for the scan cache
- Zod for config validation, YAML for the config file format