Every repo on your machine. One terminal. Zero context switching.
Install · Features · Screenshots · Keybindings · Config · FAQ
GitPulse discovers every Git repo on your machine and gives you a unified dashboard to manage them all. Stage files, generate AI commit messages, browse a beautiful commit graph, manage branches, worktrees, and stashes — without leaving the terminal.
cargo install gitpulseOr build from source:
git clone https://github.com/isaacaudet/gitpulse.git
cd gitpulse && cargo install --path .Then run:
gitpulse # scan default directories
gitpulse --scan-dir ~/code # scan specific directoryRequires: Rust 1.75+ and a terminal with Unicode support
See every repo at a glance — current branch, ahead/behind remote, dirty file count, last commit time. Color-coded: green = clean, yellow = dirty, red = unpushed. Fuzzy-filter with / to find any repo instantly.
Press Ctrl+G and GitPulse sends your staged diff to Claude or GPT and generates a conventional commit message. Edit it, tweak it, then commit. Every AI-generated message is stored in a local SQLite database for future reference.
The showpiece feature. A commit DAG rendered with Unicode box-drawing characters, color-coded per branch, handling merges and octopus merges correctly. Virtual scrolling handles repos with 50k+ commits.
Stage/unstage individual files or hunks. Commit with multiline messages. Push, pull with rebase, force push with confirmation. Create, switch, delete, merge, and rebase branches. All without leaving the TUI.
Not an afterthought. List all worktrees, see their branch and dirty status, create new ones, remove old ones, and open a terminal in any worktree with a single keystroke.
GitPulse fetches from remotes on a configurable interval (default: 5 min), so your ahead/behind counts are always current.
| Tab | What it does |
|---|---|
| 1 Changes | Staged/unstaged files, inline diff, file and hunk staging |
| 2 Commit | Multiline message editor, AI generation (Ctrl+G), push toggle |
| 3 Log | Scrollable commit history with Unicode DAG graph |
| 4 Branches | Local + remote branches, switch/create/delete/merge/rebase |
| 5 Worktrees | List/create/remove worktrees, open terminal in any worktree |
| 6 Stash | List/apply/pop/drop stashes, preview stash diffs |
| Key | Action |
|---|---|
j / k |
Move down / up |
Enter |
Select / open |
Esc |
Go back |
q |
Quit |
? |
Help overlay |
1–6 |
Switch tabs |
/ |
Fuzzy filter (dashboard) |
| Key | Action |
|---|---|
s |
Stage file |
u |
Unstage file |
a |
Stage all |
h |
Stage hunk |
d → y |
Discard changes (with confirmation) |
Ctrl+G |
Generate AI commit message |
Ctrl+Enter |
Commit |
Ctrl+A |
Amend last commit |
P |
Push |
p |
Pull (rebase) |
Shift+P → y |
Force push (with confirmation) |
| Key | Action |
|---|---|
Enter |
Switch to branch |
n |
Create branch |
d |
Delete branch |
m |
Merge |
r |
Rebase |
~/.config/gitpulse/config.toml
[scan]
roots = ["~/code", "~/work"]
exclude = ["node_modules", "target", ".cargo"]
max_depth = 5
[fetch]
interval_seconds = 300
enabled = true
[ai]
provider = "anthropic" # or "openai"
model = "claude-sonnet-4-20250514"
# Key from env: GITPULSE_AI_API_KEY
[ui]
theme = "dark" # or "light"
tick_rate_ms = 250| Env Variable | Description |
|---|---|
GITPULSE_AI_API_KEY |
API key for AI commit messages |
GITPULSE_CONFIG |
Override config file path |
GITPULSE_LOG |
Log level (trace/debug/info/warn/error) |
Events (crossterm, tick, background tasks)
│
▼
keys::map() Key → Action
│
▼
App::update() Action → State + Command ← pure, no I/O
│ │
▼ ▼
ui::draw() spawn_blocking / spawn ← async git2, AI calls
│
▼
Terminal
Elm-style architecture. App::update() is a pure state machine — it returns Command values for async work (git operations, AI calls) which the event loop executes via tokio::spawn_blocking. The UI layer is a pure function of state.
src/
├── main.rs Bootstrap, panic hook, terminal restore
├── app.rs State machine (Action/Command enums)
├── event.rs Event loop, channel plumbing
├── keys.rs Keybinding map
├── config.rs TOML config
├── ui/ Pure rendering
│ ├── dashboard.rs Repo list
│ ├── changes.rs Staged/unstaged + diff
│ ├── commit.rs Message editor + AI
│ ├── log.rs Commit history
│ ├── graph.rs Unicode graph renderer
│ ├── branches.rs Branch management
│ ├── worktrees.rs Worktree management
│ └── stash.rs Stash management
├── git/ git2 operations
│ ├── repo.rs Git ops (stage, commit, push, branch, etc.)
│ ├── diff.rs Diff parsing
│ ├── graph.rs DAG computation (active lanes algorithm)
│ └── discovery.rs Recursive .git scanner + cache
└── ai/
└── commit_msg.rs OpenAI/Anthropic API + SQLite history
The graph uses an active lanes algorithm — a single O(n) pass over commits in topological order:
- Maintain active lanes (
Vec<Option<Oid>>) — vertical columns where a parent is expected - Each commit claims its lane or opens a new one
- First parent inherits the lane; merge parents fork new lanes
- Dead lanes collapse to keep the graph compact
Each branch gets a consistent color derived from a hash of the branch name. Same branch → same color → every session.
How does it find my repos?
On first launch, GitPulse recursively scans directories you configure (or ~ by default) for .git directories. Results are cached in ~/.config/gitpulse/repos.json. Press R to rescan.
Does it work with bare repos? Yes. Bare repos show up in the dashboard but some operations (staging, worktrees) are disabled.
What about detached HEAD?
Handled. The branch column shows (detached) and most operations still work.
How are credentials handled for push/pull? GitPulse uses your system's git credential helpers (SSH agent, macOS Keychain, credential-cache, etc.). No passwords are stored by GitPulse.
Can I use it with just one repo?
Sure — gitpulse --scan-dir . scopes it to the current directory. But you'll miss the multi-repo dashboard, which is the whole point.
How does AI commit generation work? It sends the staged diff (not your code, just the diff) to the configured LLM API with a customizable prompt template. The generated message appears in the editor — you review and edit before committing. Nothing is committed automatically.
| GitPulse | LazyGit | tig | git CLI | |
|---|---|---|---|---|
| Multi-repo dashboard | ✅ | — | — | — |
| AI commit messages | ✅ | — | — | — |
| Commit graph | ✅ | ✅ | ✅ | Partial |
| Worktree management | ✅ | — | — | CLI only |
| Stash management | ✅ | ✅ | — | CLI only |
| Hunk staging | ✅ | ✅ | — | -p flag |
| Background fetch | ✅ | — | — | — |
| Fuzzy filter | ✅ | ✅ | — | — |
| Startup time | <200ms | ~500ms | ~200ms | Instant |
GitPulse does one thing well: Git operations in the terminal.
It does NOT:
- Edit files (use your editor)
- Manage PRs/issues (use
gh/glab) - Resolve merge conflicts inline (defers to
$EDITOR) - Manage Git hooks
git clone https://github.com/isaacaudet/gitpulse.git
cd gitpulse
cargo build && cargo test && cargo runPRs welcome. Open an issue first for large changes.
MIT