A terminal-first git manager written in Rust.
Interactive terminals open the TUI by default. Non-interactive runs stay on the CLI path.
Overview · Installation · Architecture · TUI · Commands · Development
gitrex packages the common git workflows into one terminal tool:
- Defaults to the TUI when both
stdinandstdoutare terminals - Falls back to CLI output for scripts, pipes, and automation
- Uses the installed
gitexecutable for repository inspection and repository mutations - Uses the installed
gitexecutable in both runtime operations and repository test fixtures - Covers status, branch inspection, recent commit review, checkout, switch, branch creation, clone, fetch, pull, and push
- Includes a branch-focused TUI with local/remote panels, branch search, branch deletion confirmation, branch-specific graph navigation, and commit actions
- Shows a loading splash while the local repository snapshot is being loaded
gitrex requires Git and a Rust toolchain with Cargo.
The recommended installation uses Cargo directly from this repository and installs the executable as gitrex.
-
Make sure Git is available. macOS can provide it through the Xcode Command Line Tools:
xcode-select --install
-
Install Rust with
rustupifcargois not already available:curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source "$HOME/.cargo/env"
-
Install GitRex:
cargo install --git https://github.com/MarcosAlves90/gitrex --locked gitrex
-
Run it from any Git repository:
gitrex
-
Install Git with your distribution package manager and verify that it is available:
git --version
-
Install Rust with
rustupifcargois not already available:curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source "$HOME/.cargo/env"
-
Install GitRex:
cargo install --git https://github.com/MarcosAlves90/gitrex --locked gitrex
-
Run it from any Git repository:
gitrex
-
Install Git and Rust with
wingetif they are not already available:winget install --id Git.Git --source winget winget install --id Rustlang.Rustup --source winget
If
rustupoffers to install the MSVC prerequisites, install them so Rust has the linker and Windows SDK required to build the executable. Reopen PowerShell after installation so the updatedPATHis loaded. -
Install GitRex:
cargo install --git https://github.com/MarcosAlves90/gitrex --locked gitrex
-
Run it from any Git repository:
gitrex
Cargo installs command-line binaries in ~/.cargo/bin on macOS/Linux and %USERPROFILE%\.cargo\bin on Windows.
If cargo install reports that GitRex is already installed but the shell returns command not found, add Cargo's binary directory to PATH.
For zsh on macOS or Linux:
grep -qxF 'export PATH="$HOME/.cargo/bin:$PATH"' ~/.zshrc \
|| echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
rehashFor bash on Linux:
grep -qxF 'export PATH="$HOME/.cargo/bin:$PATH"' ~/.bashrc \
|| echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
hash -rVerify the installation:
command -v gitrex
gitrexFor PowerShell on Windows:
$cargoBin = Join-Path $HOME '.cargo\bin'
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
if (($userPath -split ';') -notcontains $cargoBin) {
[Environment]::SetEnvironmentVariable('Path', "$cargoBin;$userPath", 'User')
}
$env:Path = "$cargoBin;$env:Path"
Get-Command gitrex
gitrexThe PowerShell command updates the current session immediately and adds Cargo's binary directory to the user PATH for future terminal sessions.
flowchart TD
A[User starts gitrex] --> B{Interactive terminal?}
B -- yes --> C[TUI router]
B -- no --> D[CLI commands]
C --> E[App state + controller]
D --> F[Command output]
E --> G[Git process adapter]
F --> G
G --> H[System Git]
H --> I[Repository]
sequenceDiagram
participant U as User
participant R as Router
participant T as TUI
participant C as CLI
participant G as GitClient
U->>R: run gitrex
R->>R: detect interactive terminal
alt interactive without subcommand
R->>T: open TUI
T->>G: refresh / branch / log operations
else subcommand given
R->>C: execute command
C->>G: read or mutate repository
end
The TUI keeps repository status visible as an informational panel and provides two navigable views:
[1] Branches[2] Graph
Status remains visible but does not receive keyboard focus because it has no panel-specific actions.
flowchart LR
H[Header] --> S[Status]
H --> B[Branches]
H --> G[Graph]
B --> L[Local branches]
B --> R[Remote branches]
G --> C[Commit actions]
B --> X[Delete confirmation]
H -. cleanup (c) .-> K[Local branch cleanup review]
H -. help (h) .-> O[Help overlay]
O --> M[Message]
1focuses branches and2focuses the graph; the same numbers are shown in their panel titlesj/kor arrow keys move within the active panelhopens the help screencopens the merged local branch cleanup reviewEscorhcloses the help screenrrefreshes the repository state
TabandShift+Tabswitch between local and remote branch panels/opens branch search and filters both local and remote refsEnteropens the branch action picker for the active panel- In the local branch panel, branch actions include checkout, switch, pull, push, and creating a branch from the selected source
- In the local branch panel, branch actions also include deleting the selected local branch after confirmation
- In the remote branch panel, branch actions include creating a local branch, checking out detached HEAD, or deleting the selected remote branch after confirmation
The cleanup review lists local branches whose tips are reachable from HEAD. Branches are selected by default; use j/k to move through the list, Space to toggle one, a to select all, and n to clear the selection. The selected branch stays in view when the list is longer than the terminal. Enter opens a scrollable warning with the selected names; press Enter again to confirm or Esc to go back or cancel. The result report also supports scrolling with j/k or PgUp/PgDn. The cleanup checks each branch again and uses Git's safe branch -d deletion. Current and base branches are protected. The operation only changes local branch refs and does not fetch, prune, push, or delete remote branches.
Press 2 to open a dedicated graph workspace. The branch/status panels are replaced by the graph and a selected-commit inspector so the available terminal area is used for
history analysis.
j/kor↑/↓move one commit at a timePageUp/PageDownmove by the currently visible graph pageHome/Endorg/Gjump to the first or last commit←/→pan a long selected commit subject manually; the graph never auto-scrolls textEnteropens commit actions for the selected commit- The selected-commit panel shows the full subject, author, date, full hash, and graph scope
- The graph follows the branch or remote ref selected in the Branches view
- Wide terminals place commit details beside the graph; narrower terminals stack details below it
- Date/hash columns disappear progressively on narrow terminals to preserve the graph lanes and commit subject
Enter opens actions for the selected commit. Compare asks for another commit or branch, resolves both references, and shows a scrollable diff-stat summary with at most 250 path entries. It does not move refs, change the index or worktree, or contact a remote. Use j/k, the arrow keys, or PgUp/PgDn to review long results.
Cherry-pick requires choosing and reviewing an existing local destination branch. The index and worktree, including untracked files, must be clean before Git switches branches. GitRex also protects ignored paths: it refuses a switch that would overwrite one and checks the selected commit's changed paths before switching. After an attempt, the destination stays active. Real file conflicts refresh the status and remain for you to resolve and finish with git cherry-pick --continue or cancel with git cherry-pick --abort. If a patch is already applied and Git stops with an empty pick, GitRex reports that state separately and gives git cherry-pick --skip or --abort guidance.
Reset current branch is available only when the graph shows the checked-out local branch. Choose Soft, Mixed, or Hard; Soft is selected by default. Soft moves the branch tip and leaves the index and worktree unchanged. Mixed also resets the index while keeping worktree files. Hard overwrites tracked index and worktree files. Its separate destructive review lists dirty paths and any ignored/untracked paths that collide with the target tree; a collision blocks reset until you move or remove the path. GitRex rechecks the current branch, HEAD, and path collisions immediately before reset. These actions run asynchronously and never stash changes or resolve conflicts automatically.
The help screen is scrollable:
j/kor↑/↓scroll the shortcuts panel- A scrollbar shows position and range
- The bottom
Messagepanel stays fixed and shows the close hint
| Command | Description |
|---|---|
gitrex |
Opens the TUI in interactive terminals |
gitrex status |
Prints the current branch, upstream, divergence, and working tree state |
gitrex branch |
Lists remote branches grouped by remote and local branches with sync status |
gitrex log --limit <n> |
Shows recent commits from the current branch history, defaulting to 20 |
| `gitrex inspect [--scope minimal | change |
| `gitrex diff [--staged | --base |
gitrex show <commit> |
Shows commit metadata and its first-parent diff |
gitrex compare <left> <right> |
Compares local refs, their merge base, divergence, and unique commits |
gitrex change-context --base <ref> |
Combines committed changes since a base with the current working tree state |
gitrex checkout <target> [--expect-*] [--format json] |
Checks out an existing branch or ref |
gitrex switch <target> [--dry-run] [--expect-*] [--format json] |
Plans or switches to a branch |
gitrex create-branch <name> [--from <target>] [--dry-run] [--expect-*] [--format json] |
Plans or creates a new branch |
gitrex clone <repository> [directory] |
Clones a repository to an optional destination |
gitrex fetch [remote] [--dry-run] [--expect-*] [--format json] |
Plans or refreshes and prunes remote-tracking refs |
gitrex pull [remote] [branch] [--dry-run] [--expect-*] [--format json] |
Plans or pulls updates from a remote and branch |
gitrex push [remote] [branch] [--dry-run] [--expect-*] [--format json] |
Plans or pushes commits to a remote and branch |
gitrex cleanup [options] [--dry-run] [--expect-*] [--format json] |
Previews merged local branches; requires --yes to delete them |
gitrex tui |
Forces the TUI explicitly |
gitrex cleanup
gitrex cleanup --base main --exclude keep-this --exclude release/next
gitrex cleanup --base main --remote origin --remote upstream --yesThe default base is the current HEAD. Use --base <ref> to choose another commit or ref, --exclude <name> one or more times to preserve exact local branch names, and --remote <name> one or more times to include branches whose upstream uses any selected configured remote. Remote filtering reads local Git configuration and does not contact the remotes. Without --yes, the command only prints the candidates. With --yes, it rechecks each candidate against the same filters and attempts git branch -d -- <name>, reporting deleted, skipped, and failed branches separately.
Cleanup is based on commit ancestry: a branch tip must be an ancestor of the base commit. A squash merge or rebase can preserve the changes while producing different commit IDs, so those branches may not appear as merged. Git's safe deletion check is repeated for every branch and may still refuse a branch when Git sees unmerged commits.
switch, create-branch, cleanup, fetch, pull, and push accept --dry-run. These plans use GitRex analysis against local state and do not contact remotes or mutate refs, the index, the worktree, or remote refs. The plan marks this as planning_source: gitrex_analysis; network_access_required describes the eventual operation, while network_access_during_planning is false. git_provided_dry_run identifies a plan that actually used Git's dry-run output.
Supported repository mutation commands accept any of --expect-head <full-sha>, --expect-branch <name>, and --expect-upstream <ref>. GitRex checks the supplied values and the planned refs again immediately before invoking Git. A mismatch exits with PRECONDITION_CHANGED; JSON error details include expected and observed state, and identify a changed ref when applicable.
Use --format json on checkout, switch, create-branch, cleanup, fetch, pull, and push to receive an operation plan or receipt through the shared protocol. Receipts report whether Git state changed, before/after identifiers, observed effects, and the verification result. Remote effects are listed as confirmed only when a follow-up remote read observes them. An operation can return VERIFICATION_FAILED after Git reports success if its expected postcondition cannot be confirmed.
These context commands read only local Git state. They never fetch. Reference arguments are resolved to full commit IDs before comparison commands run.
inspect defaults to --scope full. minimal returns repository identity, HEAD, upstream divergence, working-tree counts, and conflict state without path lists, branch refs, or history. change adds staged, unstaged, untracked, and conflict paths. branches adds local and remote refs without path lists or history. full includes both path lists and branch refs plus recent history. Path lists default to 100 entries per group (--max-paths); branch lists default to 100 (--max-branches); history defaults to 20 commits (--history-limit). Each list reports its total count and whether the displayed list was truncated.
diff with no mode follows Git's default and shows unstaged tracked changes. --staged compares the index with HEAD; --base <ref> compares the base with the current worktree, including staged and unstaged tracked changes; and --from <ref> --to <ref> compares two commits. Text output includes a patch. JSON output includes patch text only with --include-patch. Patches default to 64 KiB and can be raised to 1 MiB with --max-patch-bytes; the output reports returned and total bytes and an explicit truncation flag. Changed paths default to 100 entries and can be adjusted with --max-paths.
show <commit> uses the first parent as the comparison point for merge commits. compare <left> <right> reports commits unique to the left as ahead and commits unique to the right as behind; its path summary compares left to right. change-context --base <ref> reports commits and file changes from the base to HEAD, then reports staged, unstaged, untracked, and conflict state separately. Commit lists default to 20 entries and can be adjusted with --max-commits.
status, branch, log, inspect, diff, show, compare, and change-context keep human-readable output by default, except change-context defaults to JSON. Add --format json to receive the versioned machine protocol. Mutating commands that support --format return plans for dry-runs and receipts after execution. Context command limits and scope options are supported in both formats. capabilities describes the supported commands and can also be printed as JSON:
gitrex status --format json
gitrex branch --format json
gitrex log --limit 5 --format json
gitrex inspect --scope minimal --format json
gitrex diff --base main --format json
gitrex show HEAD --format json
gitrex compare main feature --format json
gitrex change-context --base main
gitrex capabilities --format json
Every protocol response has schema_version (integer), operation (command name string), and ok (boolean). A successful response contains data; a failed response contains error; warnings is an optional array of strings. The envelope fields that do not apply are omitted.
For example, a failed status request outside a repository is:
{
"schema_version": 1,
"operation": "status",
"ok": false,
"error": {
"code": "NOT_A_REPOSITORY",
"message": "repository not found",
"retryable": false
}
}
The stable data fields are:
| Operation | Fields and JSON types |
|---|---|
| status | branch_name: string; upstream: string or null; ahead and behind: integers; files: array of objects with code and path strings |
| branch | branches: array of objects with name (string), current (boolean), upstream (string or null), commit (string), subject (string), and kind (local or remote) |
| log | commits: array of objects with hash, author, date (YYYY-MM-DD), and subject, all strings |
| inspect | scope; repository identity; HEAD; optional upstream; working-tree groups with counts and optional paths; conflict summary; optional bounded branches and history |
| diff | mode; resolved left/right commit IDs where applicable; changed paths and available line statistics; counts; truncation flags; optional bounded patch |
| show | full commit identity, parents, author timestamp, subject and body, plus changed paths, statistics, and optional patch |
| compare | resolved refs; merge bases; ahead/behind counts; bounded unique commit arrays with counts and truncation flags; path summary |
| change-context | resolved base and HEAD; merge bases; bounded commits since base; committed diff; working-tree groups and conflicts |
| capabilities | gitrex_version (string); protocol_schema_version (integer); supported_output_formats (string array); operations (array); authorization (object) |
| mutation plan | operation identifier; effects and risk class; expected preconditions, their planned state, and the observed state; expected local/remote effects; network requirements; planning source; refs and immutable commit IDs |
| mutation receipt | operation identifier; state_changed; before/after identifiers; confirmed local/remote effects; verification status and checks |
Each capabilities operation has name (string), legacy effects (array), classification (effects and risk_class), and output_formats (string array). The legacy effects array keeps the protocol-v1 network_access value for compatibility. classification.effects and classification.risk_class use read_only, local_mutation, network_read, remote_mutation, and destructive. The authorization object has granted (boolean, always false) and note (string). Empty collections are returned as empty arrays.
Classification effects list every kind of change an operation can perform. risk_class describes the operation's authorization risk; it does not authorize execution. For the composite tui operation, the classification is the union of its available actions, including destructive operations.
Error code is the stable machine identifier. message is a human-readable diagnostic string and may change. retryable is an optional boolean and is omitted when uncertain. Optional details is an object: REFERENCE_NOT_FOUND includes reference (string), COMMAND_FAILED includes command (string) and may include exit_code (integer), DIVERGED includes ahead and behind (integers), and PRECONDITION_CHANGED includes expected/observed state plus an optional changed reference. I/O and backend failures share BACKEND_ERROR.
| Code | Meaning |
|---|---|
| GIT_NOT_INSTALLED | Git could not be started because it is unavailable |
| NOT_A_REPOSITORY | The current directory is not inside a Git repository |
| REFERENCE_NOT_FOUND | A requested Git reference does not exist |
| COMMAND_FAILED | A Git command returned a failure status |
| DIVERGED | A pull cannot fast-forward because local and remote histories diverged |
| PRECONDITION_CHANGED | Repository state changed from the expected or planned values; no mutation was started |
| VERIFICATION_FAILED | Git returned successfully, but the expected post-operation state could not be confirmed |
| BACKEND_ERROR | GitRex or operating-system I/O failed |
| PARSE_ERROR | GitRex could not parse Git output |
| INVALID_UTF8 | Git output was not valid UTF-8 |
capabilities includes gitrex_version, protocol_schema_version, supported_output_formats, and an ordered operations array. Each operation lists its name, legacy effects, classification, and output_formats. The legacy effects are read_only, local_mutation, network_access, and remote_mutation; classification.effects adds the precise network-read and destructive classes. authorization.granted is always false: discovery describes availability and does not authorize execution.
Exit status is 0 on success, 1 for a Git operation failure, and 2 for invalid command syntax or option values. JSON operation failures write the envelope to stdout and retain a readable diagnostic on stderr. Clap usage errors remain human-readable.
The protocol schema version is independent of the GitRex package version. Clients should check schema_version and operation, use error codes instead of parsing messages, and ignore unknown object fields and operation entries. Additive optional fields are compatible; removing or renaming fields, changing a field's type or meaning, or changing required behavior requires a schema-version increment. Versioned response fixtures live in tests/fixtures/protocol/v1/; update them only with the matching protocol-version change.
branch: main
upstream: origin/main
working tree: clean
remote branches:
origin
main
feature/login
upstream
main
local branches:
* main [synced: origin/main, upstream/main]
feature/login [local-only]
release [local-only]
cargo build --releasecargo runTo force the TUI explicitly:
cargo run -- tuicargo run -- status
cargo run -- branch
cargo run -- log --limit 20cargo buildcargo test- Repository rules live in CONTEXT.md
- Format guidance lives in CONTEXT-FORMAT.md
- Rust 2021
clapfor CLI parsingcrosstermfor terminal control- system Git for repository inspection and mutation execution
- system Git for repository test fixtures
ratatuifor the TUIanyhowandthiserrorfor error handling
- The CLI path prints a help hint when no subcommand is provided outside an interactive terminal.
- The TUI is the primary interactive experience.
- Read-only commands and TUI snapshots do not perform network I/O implicitly.
- Run
gitrex fetchwhen you want to refresh remote-tracking refs explicitly. - Explicit pulls are fast-forward-only and reject diverged histories without moving local HEAD.
- Captured Git commands disable terminal credential prompts and rely on configured credential helpers or agents.
