- Rust 100%
|
All checks were successful
CI / msrv (push) Successful in 6m26s
CI / check (rust) (push) Successful in 9m50s
CI / deny (push) Successful in 5m48s
CI / check (windows) (push) Successful in 13m53s
Release / build-linux (push) Successful in 5m3s
Release / build-windows (push) Successful in 6m31s
Release / publish (push) Successful in 3m31s
|
||
|---|---|---|
| .forgejo/workflows | ||
| crates | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| deny.toml | ||
| LICENSE | ||
| README.md | ||
| RELEASING.md | ||
Galax
Navigate your git galaxy.
Galax (gx) is a suite of git power tools that live in one fast, dependency-free
binary. Browse your commit graph as a constellation, jump through diffs, juggle
worktrees, craft conventional commits, clean up stale branches, and browse your
stashes — all without leaving the terminal.
Pure Rust, no C dependencies, works the same on Linux, macOS, and Windows (yes, even in tmux).
Install
| Method | Command |
|---|---|
| crates.io (any platform with Rust) | cargo install galax |
| Homebrew (macOS / Linux) | brew tap byjokese/tap https://code.byjokese.net/byjokese/homebrew-tap.git then brew install byjokese/tap/galax |
| Prebuilt binary (Linux / Windows) | Download from the latest release and put gx on your PATH |
All install methods give you the gx binary. Building from source:
git clone https://code.byjokese.net/byjokese/galax.git
cd galax
cargo install --path crates/galax
Building from source (including cargo install) needs Rust 1.90 or newer.
The prebuilt binaries have no toolchain requirement.
Shell setup (do this next)
gx wt (no verb) opens an interactive picker so you can jump into any worktree.
But a picker running as a normal subprocess cannot change the directory of the
shell that launched it — that's a hard OS limitation, not a gx bug. To get
the "pick a worktree, land in its directory" experience, add one line to your
shell's startup file. It defines a gx shell function that wraps the real
binary: it runs gx, and if the picker chose a worktree, the wrapper cds
your actual shell there.
| Shell | Add to | Line |
|---|---|---|
| bash | ~/.bashrc |
eval "$(gx shell-init bash)" |
| zsh | ~/.zshrc |
eval "$(gx shell-init zsh)" |
| fish | ~/.config/fish/config.fish |
gx shell-init fish | source |
| PowerShell | $PROFILE |
Invoke-Expression (gx shell-init powershell | Out-String) |
Without this, gx wt still works — it just prints the chosen path instead of
cd-ing there, same as any other CLI output.
Usage
Bare gx (no subcommand) prints repo status. Most other tools open an
interactive TUI when called bare, and take a verb for scriptable CLI use:
gx # repo status
gx status --json # machine-readable status
gx graph # interactive commit graph browser
gx graph -n 50 # limit to 50 commits
gx wt # interactive worktree picker (cd's your shell — see Setup above)
gx wt list --json # scriptable: list worktrees as JSON
Inside any TUI: / fuzzy search, Enter drill in, q / Esc quit or close,
? help overlay listing every binding (all rebindable via config).
Commands
-
gx/gx status— repo status: branch, ahead/behind, staged/modified/ untracked counts, worktree list.--jsonfor machine-readable output. -
gx graph— interactive commit graph browser: lane-based layout in Unicode box-drawing, commit detail pane, refs pane, live fuzzy search, and a full-screen diff view per commit. Rows carry git-style colored decorations (HEAD -> main, branches, tags, remotes), the short SHA, and anSmarker on commits that carry a GPG/SSH signature (presence only —gxnever verifies signatures). On image-capable terminals the graph column renders as smooth pixel graphics (thick lines, curved corners, ringed HEAD node) — automatically on kitty, Ghostty, iTerm2, WezTerm, Windows Terminal, foot, and tmux on a kitty-class host; everywhere else it falls back to the classic text renderer.-n, --max-count <N>limit commits loaded ·--order <chrono|topo>(defaultchrono). Keys:j/knavigate ·g/Gtop/bottom ·Entertoggle detail ·dopen commit diff ·rtoggle refs pane ·/search,n/Ncycle matches ·ccopy commit hash ·stoggle the diff view between inline and side-by-side. -
gx diff [REV]— a one-shot diff viewer. With no arguments, shows the working tree;--stagedshows the index vsHEAD;REVshows a commit against its first parent, orA..Bfor a range.--staged(conflicts withREV). Keys:Tabswitch file list / hunk pane ·Shift-J/Shift-Knext/prev file ·]/[next/prev hunk ·stoggle inline / side-by-side layout. -
gx wt [COMMAND]— worktree manager. Baregx wtopens the interactive picker (needs shell-init — see Setup above); verbs are scriptable:list— list worktrees.--json.add <branch> [--from <ref>]— create a worktree for<branch>, running any configured setup hooks afterward.rm <name> [--force]— remove a worktree by name or path;--forcefor a dirty worktree.
-
gx branches [COMMAND]— branch cleanup. Baregx branchesopens an interactive TUI:Spacetoggles a candidate (merged-into-base or upstream-gone branches only — never the current or base branch),Enterarms ay/ndelete confirmation. Verbs:list [--base <branch>]— list branches with their state (Active/Merged/ Gone).--json.clean [--dry-run] [--yes] [--base <branch>]— delete every merged/gone branch. Refuses to run without--dry-runor--yes.
-
gx commit [-a|--all]— interactive Conventional Commits wizard: Kind → Scope → Subject → Body → Breaking → Confirm, then runsgit commit -m <rendered message>(so hooks, signing, etc. behave exactly as they do on the command line).-a, --allstages all tracked modifications first (git commit -a). The body is a single-line field in this wizard — for a multi-line body, run plaingit commit(no-m) to open your real editor. -
gx stash [COMMAND]— stash browser. Baregx stashopens an interactive TUI with a diff preview per stash:aapply,ppop,xdrop, each armed behind ay/nconfirm. Verbs:list— list stashes.apply <index>/pop <index>— apply (optionally removing) a stash.drop <index> --yes— remove a stash without applying it. Refuses without--yes.
(
gx stashbrowses and manages existing stashes; creating one is a one-liner in git itself —git stash push.) -
gx repos [COMMAND]— multi-repo fleet dashboard. Baregx reposopens instantly from a cached snapshot (noting its age in the status line) while rescanning the configured watch folders in the background; verbs are scriptable:status— scan and print each repo's branch, ahead/behind, and staged/modified/untracked counts.--json.fetch—git fetch --all --pruneacross every repo in parallel.--json.pull— fast-forward-only pull across every repo in parallel (see Fleet safety rules below).--json.
Dashboard keys:
spacetoggle the current row's selection ·Shift-Aselect/deselect every row ·ffetch ·upull (both act on the selection, or every repo if nothing is selected; each arms ay/nconfirm naming the count) ·/search by name or branch,n/Ncycle matches ·?help.See Fleet below for the
[repos]config block and the safety rules the dashboard is built around. -
gx shell-init <bash|zsh|fish|powershell>— prints the shell wrapper function described in Setup above. Never touches your shell directly; youeval/sourceits output yourself.
Configuration
gx reads config.toml from your OS config directory (e.g.
~/.config/gx/config.toml on Linux, ~/Library/Application Support/gx/ on
macOS), or from $GX_CONFIG_FILE if set.
Theme
Pick a built-in base theme with ui.theme ("default" or "light"), then
override individual colors under [theme]:
[ui]
theme = "light" # built-in: "default" (dark terminals), "light" (bright terminals)
All TUI colors are overridable via a [theme] section. Any subset of keys;
values are color names ("cyan", "lightred"), #RRGGBB hex, or 0-255
indexed colors:
[theme]
sha = "yellow" # short commit id column
branch = "green" # local-branch badges
remote = "red" # remote badges
tag = "yellow" # tag badges
head = "cyan" # HEAD -> badge text (the ◉ node keeps its lane color)
signature = "green" # signed-commit marker
search_match = "#5c5200" # search match background
diff_added_bg = "#1c3a24" # added diff line background
diff_removed_bg = "#3d1f23" # removed diff line background
graph_palette = ["cyan", "magenta", "yellow", "green", "blue", "red"]
graph_palette cycles by lane, so it can be any length. The built-in
default is six truecolor (RGB hex) entries; the example above overrides it
with a six-color palette of named colors instead, but a list of any length
works -- a shorter one cycles sooner, a longer one keeps more lanes
visually distinct before repeating.
Graph
[graph]
renderer = "auto" # auto | image | text
protocol = "auto" # auto | kitty | kitty-unicode | iterm2 | sixel
style = "rounded" # rounded | angular
auto only enables images on positively identified terminals and always
falls back to text inside multiplexers without graphics passthrough
(herdr, Zellij, screen). tmux works via kitty's unicode placeholders when
the host terminal is kitty-class. Force a specific protocol if you know
your setup passes graphics through.
Diff
[diff]
view = "inline" # inline | split
split lays diffs out side-by-side (old left, new right) when the pane is
at least 100 columns wide, falling back to inline on narrower terminals.
s toggles the layout live in the gx diff and graph diff views.
Fleet
gx repos operates on every git repository found under the paths in
[repos].watch_folders, walked to scan_depth directories deep. Configure it
in your config.toml (bare gx repos status prints the exact expected path
if no watch folders are set; $GX_CONFIG_FILE overrides it):
[repos]
watch_folders = ["~/code", "~/work"]
scan_depth = 2 # how deep under each watch folder to look for a `.git`
parallelism = 0 # threads for fetch/pull; 0 = auto (rayon's default)
Fleet safety rules
These are load-bearing, not configurable — they are why fleet operations are built the way they are:
-
Fetch/pull never ask a human for anything. Nothing in a fleet operation can put a prompt or a dialog in front of you: git's terminal prompt (
GIT_TERMINAL_PROMPT=0), askpass helpers (GIT_ASKPASS,core.askPass,SSH_ASKPASS), ssh passphrase and host-key confirmations (BatchMode=yes), and interactive credential helpers (credential.interactive=false,GCM_INTERACTIVE=never— Git for Windows enables Git Credential Manager by default) are all disabled. A repo that genuinely needs auth fails fast, for that repo alone, instead of hanging its thread — and, once the whole pool is stuck the same way, the entire batch — or popping one GUI dialog per repo.Your credential helper is not disabled, only its ability to interact: it can still answer silently from the keychain, so unattended fetches of private repos keep working. Use an ssh-agent or a helper with stored credentials for any remote that needs auth.
-
pullis fast-forward only. It never merges and never rebases. A repo that is dirty, detached, has no upstream, or has diverged from its upstream is skipped with a stated reason and left completely untouched. -
Every operation is bounded in time. Rule 1 is enforced with settings a determined credential helper is free to ignore — and
pullfast-forwards withgit merge --ff-only, which still runs your repo's hooks, and a hook can do anything, including wait on input. So each git subprocess also gets a watchdog: if it outlives the timeout it is killed — along with everything it spawned, since git does the work that hangs (ssh, a hook, a credential helper) in a child that would otherwise outlive it — and the repo is reported as a failed row, rather than silently consuming a worker for the rest of the run. This is what actually guarantees thatgx repos fetchover a large fleet terminates.The bound is per git invocation. A
pullis two of them (a fetch, then a fast-forward), so a repo wedged on both legs takes up to twice the timeout before it gives up. -
Aborting aborts. Ctrl-C, or quitting the dashboard while an operation is running, stops the git processes too. Without this they would keep going in the background —
git merge --ff-onlystill fast-forwarding your repos seconds after gx had left the screen.
Roadmap
- status — repo status, human or
--json - graph — commit graph browser
- diff — diff navigator
- wt — worktree manager + shell-init cd integration
- commit — semantic (conventional) commit wizard
- branches — branch cleanup (merged/gone classification)
- stash — stash browser
- fleet — multi-repo dashboard
- polish & release — themes, docs pass, packaged release (Forgejo releases + crates.io)
Design principles
- One binary. Everything ships in
gx; no plugins, no runtime deps. - Reads are fast, writes are safe. Reads go through gix
in-process; anything that mutates a repo shells out to your
git, so hooks, signing, and config behave exactly as they do on your command line. - Terminal-first. Unicode box-drawing, no image protocols — works over SSH, in tmux, and on Windows.
Development
cargo build
cargo test
cargo fmt --all && cargo clippy --workspace --all-targets -- -D warnings
cargo run -- graph # run against the current repo
Workspace layout: gx-core (headless domain logic), gx-tui (shared TUI kit),
galax (the gx binary), gx-testkit (test fixtures).
License
MIT