One model, every command
List candidates → filter and pick in the fuzzy finder with a preview → run the git operation. Learn it once and every subcommand behaves the same way.
Pick, search, and trace your way through git.
You should not have to remember a branch name or a commit hash to
get work done. Every fuzgit subcommand follows the same model:
build the candidate list, filter and pick it in a fuzzy finder
(with a preview), then run the git operation. The fuzzy finder is
skim, embedded as a
library — no external fzf or sk binary is
required.
package fuzgit · command gz · written in Rust · MIT
Picking
The two commands where a fuzzy finder pays off immediately:
gz branch and gz stash. Type the fragment
you do remember, let the preview confirm it is the right one, and
press Enter to run the git operation.
$ gz branch --all
> * main
feature/login
origin/feature/search
* as git branch, and
the preview shows the 50 most recent commits of the
highlighted branch (git log --oneline --decorate).
With --all, remote-tracking branches join the list
— picking origin/feature/search switches by the
short name, so git’s DWIM creates the tracking local branch.
$ gz stash apply
> stash@{0}: On main: half-done auth refactor
stash@{1}: On feature/search: draft of the search form
apply / pop /
drop are stash@{n}: <message>, so
you filter by what you wrote, not by index. The preview
is git stash show -p --color=always, and
drop — the one step that cannot be undone — asks
for confirmation ([y/N]) first.
$ gz stash push -m "half-done auth refactor"
>> M src/auth.rs
> M src/session.rs
M README.md
push picks files rather than a stash.
Tab selects several of them and only the files you
picked are stashed — everything you left alone stays in the
working tree. Staged changes are stashed too, so the preview is
the diff against HEAD (git diff HEAD);
-u adds untracked files to the list.
In one go
The same model, except that what you pick is a set:
gz fetch -s updates several repositories and
gz pull brings several branches up to their upstream —
one selection, one run, one summary.
$ gz fetch --siblings
The current repository is preselected. Tab: toggle the selection / Enter: fetch | 1 excluded (no remote / bare)
>> mike origin/main
alpha origin/main
zulu origin/main
-s (--siblings)
scans the parent directory of the current worktree root
one level deep only and offers every directory that
contains a .git; a line reads
<directory> <remote>/<current branch>.
Repositories that cannot be fetched are excluded, never silently
— the number skipped is in the header.
$ gz pull
The current branch is preselected. Tab: toggle the selection / Enter: integrate with a fast-forward only | 2 excluded (no upstream / remote not registered / in use by another worktree)
>> * main → origin/main
feature-a → origin/feature-a
$ gz pull
[1/4] main
[2/4] alpha
[3/4] diverged
[4/4] zeta
3 succeeded / 1 failed (failed: diverged)
A branch that could not fast-forward can be integrated with `gz sync --rebase` or `gz sync --merge` after switching to it
[<n>/<total>] so you can tell whose output
git is printing; a failure never stops the run, and the
tally comes at the end. gz fetch --siblings reports
the same way. fuzgit only points at the next step — it never
starts gz sync for you.
Note: the terminal excerpts above show fuzgit’s
English output, which is the default; the same lines come out in
Japanese with --lang ja.
Everything git prints (update tables, conflicts, authentication
prompts) comes straight from git.
Why fuzgit
List candidates → filter and pick in the fuzzy finder with a preview → run the git operation. Learn it once and every subcommand behaves the same way.
Candidate lists and previews are built from local repository data only. A preview is regenerated on every cursor move, so a network round trip there would block the whole display.
gz fetch, gz pull and
gz sync use the network. Everything else is local
— pushing is left to plain git push.
Destructive operations confirm first, gz pull is
fast-forward only, merge shows a conflict prediction, pushing is
left to git and history is never rewritten automatically.
git is always executed with an argument array, never through a shell, and previews run git from Rust instead of handing skim a command string. Picked values are verified against the candidate list before they reach git.
Candidates are read with
gitoxide (gix).
Anything that would need one git process per
candidate — ahead/behind across repositories, for instance — is
moved into the preview so the list appears immediately.
Language
Messages, confirmation prompts, finder headers and
--help come in English and Japanese. English is the
default, and a single git config entry makes it Japanese
everywhere.
git config --global fuzgit.lang ja # persistent (--local sets it per repository)
gz --lang ja branch # one-off, on any subcommand
| Priority | Source |
|---|---|
| 1 |
--lang <ja|en|auto> — a global option,
accepted by every subcommand
|
| 2 | FUZGIT_LANG environment variable |
| 3 |
git config fuzgit.lang — system / global /
local / worktree all apply as usual
|
| 4 |
LC_ALL → LC_MESSAGES →
LANGUAGE → LANG
|
| 5 | fallback: en |
Layers 1–3 are explicit instructions to fuzgit, so a value
other than ja / en / auto
stops with an error. Layer 4 only describes the environment, so a
value fuzgit cannot interpret — C and
POSIX included — is not an error and resolution moves
on. auto skips the remaining explicit layers and reads
the environment. There is no fuzgit configuration file: it borrows
git’s fuzgit.lang key, which is read without
starting a git process and works outside a repository
too.
Two limits. fuzgit tells the git commands it runs
which language to speak, but whether git has that translation
is not guaranteed — it depends on the git build (NLS) and the
installed locale data, and git upstream ships no Japanese
catalog, so git’s own output stays English even with
ja. And the text clap prints on its own
(Usage:, Options:,
Commands:, parser errors) stays English,
because clap 4 has no localization hook; fuzgit’s own
descriptions in --help do switch.
Reference
gz <subcommand> [options]. Running
gz with no arguments — or gz --help —
lists the subcommands.
| Subcommand | What it does | Selection |
|---|---|---|
gz branch |
Pick a branch and switch to it (subcommands also create, delete and tidy up branches) | single / depends on subcommand |
gz log |
Trace the commit history and print the full hash to stdout | single |
gz cherry-pick
|
Pick commits and cherry-pick them | multiple |
gz restore |
Pick files to restore or unstage | multiple |
gz add |
Pick unstaged and untracked files and stage them | multiple |
gz stash <subcommand>
|
Stash changes away, and search stashes to apply or drop them | depends on subcommand |
gz tag |
Pick a tag to print, switch to, or diff | single |
gz reflog |
Trace the HEAD reflog and recover commits you thought were lost | single |
gz commit |
Pick changed files and commit only those | multiple |
gz fixup |
Pick the commit to amend and create a fixup commit | single |
gz merge |
Pick the branch to merge (recovery menu while one is in progress) | single |
gz rebase |
Pick the base to rebase onto (recovery menu while one is in progress) | single |
gz revert |
Pick the commits to undo and revert them | multiple |
gz status |
List changed files and act on the ones you pick (two-step selection) | multiple → single |
gz diff |
Pick what to compare and show the diff | depends on mode |
gz fetch |
Decide what to fetch and fetch it (--siblings
also fetches the repositories next door;
uses the network)
|
single / multiple with --siblings |
gz pull |
Pick branches and bring them up to their upstream in one go (fast-forward only; uses the network) | multiple |
gz sync |
Sync the current branch with its upstream (uses the network) | none |
gz worktree |
List and manage worktrees | single |
Install
fuzgit is not published to crates.io yet, so install it from a local clone.
git clone https://github.com/hatohato25/fuzgit.git
cd fuzgit
cargo install --path .
This installs ~/.cargo/bin/gz (the package is
fuzgit, the command is gz). To try it
without installing:
cargo build --release
./target/release/gz --help
git; gix is used to read repository data.