Skip to content

isaacaudet/gitpulse

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitPulse

Every repo on your machine. One terminal. Zero context switching.

Rust License: MIT CI


GitPulse Dashboard

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.


Install

cargo install gitpulse

Or 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 directory

Requires: Rust 1.75+ and a terminal with Unicode support


✨ Features

Multi-Repo Dashboard

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.

AI Commit Messages

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.

Beautiful Commit Graph

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.

Full Git Workflow

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.

First-Class Worktrees

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.

Background Fetch

GitPulse fetches from remotes on a configurable interval (default: 5 min), so your ahead/behind counts are always current.


Screenshots

Changes — Split pane with staged/unstaged files and inline diff

GitPulse Changes View

Commit Graph — Branch visualization with per-branch coloring

GitPulse Commit Graph

All Six Tabs

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

⌨ Keybindings

Navigation

Key Action
j / k Move down / up
Enter Select / open
Esc Go back
q Quit
? Help overlay
16 Switch tabs
/ Fuzzy filter (dashboard)

Git Operations

Key Action
s Stage file
u Unstage file
a Stage all
h Stage hunk
dy Discard changes (with confirmation)
Ctrl+G Generate AI commit message
Ctrl+Enter Commit
Ctrl+A Amend last commit
P Push
p Pull (rebase)
Shift+Py Force push (with confirmation)

Branches

Key Action
Enter Switch to branch
n Create branch
d Delete branch
m Merge
r Rebase

⚙️ Config

~/.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)

🏗 Architecture

  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

🔀 How the Commit Graph Works

The graph uses an active lanes algorithm — a single O(n) pass over commits in topological order:

  1. Maintain active lanes (Vec<Option<Oid>>) — vertical columns where a parent is expected
  2. Each commit claims its lane or opens a new one
  3. First parent inherits the lane; merge parents fork new lanes
  4. 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.


🤔 FAQ

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.


Why GitPulse?

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

Non-Goals

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

Contributing

git clone https://github.com/isaacaudet/gitpulse.git
cd gitpulse
cargo build && cargo test && cargo run

PRs welcome. Open an issue first for large changes.


License

MIT


Built with Rust · ratatui · git2

Made for developers who live in the terminal.

About

The Git dashboard your terminal deserves. All repos, AI commits, beautiful graphs.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages