fuzgit documentationfuzgit ドキュメント
fuzgit is a git CLI built around picking, searching and tracing with a fuzzy finder. The goal is to let you finish everyday git work without remembering branch names or commit hashes exactly: you narrow the list down and pick.
Every subcommand follows the same model —
build the candidate list → filter and pick it in the
fuzzy finder (with a preview) → run the git
operation. The fuzzy finder is
skim embedded as a
library, so no external fzf or sk binary
is needed.
- Package name:
fuzgit - Command (binary) name:
gz
fuzgit speaks English and Japanese, English being the default (see Language). Console excerpts on this page show the default English display.
fuzzy finder で「選ぶ」「探す」「辿る」ことを軸にした git 操作 CLI ツールです。
ブランチ名やコミットハッシュを正確に覚えていなくても、絞り込みと選択だけで日常的な
git 操作を完結できることを目指しています。すべてのサブコマンドが
候補一覧の取得 → fuzzy finder で絞り込み・選択(+プレビュー)→
git 操作の実行という同じ操作モデルに従います。fuzzy finder は
skim をライブラリとして組み込んでいるため、
外部の fzf / sk バイナリは不要です。
- パッケージ名:
fuzgit - 実行コマンド名(バイナリ名):
gz
Requirements前提条件 #
-
git on the system (required). fuzgit reads the
repository with gix,
but every write (
switch,cherry-pick,restore,add,stash…) and every coloured diff preview runs the systemgit. Without it onPATH, fuzgit stops with “git was not found. Install git and make sure it is on your PATH”. -
Git 2.38 or newer — only for the conflict
prediction of
gz merge. The prediction needsgit merge-tree --write-tree. On older git the prediction is skipped and the merge still runs; the confirmation prompt says so. -
Git 2.32 or newer — only for the
gz stashpreview. It asksgit stash showfor--include-untracked. Older git shows an error in the preview pane; picking and applying a stash still works. Anything that satisfies the 2.38 above satisfies this too. - A stable Rust toolchain — only to build from source. Rust 1.85 or newer (the crate uses edition 2024); development is verified with 1.95.0.
-
システムの
git(必須)
リポジトリの読み取りには gix を使いますが、書き込み(switch・cherry-pick・restore・add・stashなど)と プレビュー用の色付き差分は、いずれもシステムのgitを 実行します。PATH 上に無い場合は「git コマンドが見つかりません」と 表示して停止します。 -
Git 2.38 以降 —
gz mergeのコンフリクト予測にのみ必要
予測にはgit merge-tree --write-treeを使います。それより古い git では予測だけを省略し、merge はそのまま実行します (省略した旨は確認プロンプトに表示されます)。 -
Git 2.32 以降 —
gz stashのプレビューにのみ必要
git stash showに--include-untrackedを渡すためです。 これより古い git ではプレビューにエラーが出ますが、stash の選択と適用は動きます。 上の 2.38 を満たしていれば、こちらも満たされます。 -
stable の Rust ツールチェイン — ソースからビルドする場合のみ
Rust 1.85 以降(edition 2024 のため)。開発時の確認は 1.95.0 です。
Installationインストール #
macOS — Homebrew
brew install hatohato25/fuzgit/fuzgit
Linux / WSL — install script
curl -fsSL https://raw.githubusercontent.com/hatohato25/fuzgit/main/install.sh | sh
It downloads the release tarball for your machine,
verifies its SHA-256 checksum, and puts
gz in ~/.local/bin. No
sudo, and nothing outside that directory. If that
directory is not on PATH, the script prints the line
to add — it does not edit your shell profile for
you.
| Option | Environment variable | Description |
|---|---|---|
--version <TAG> | FUZGIT_VERSION | Release to install (defaults to the latest) |
--bin-dir <DIR> | FUZGIT_BIN_DIR | Where to put gz (defaults to ~/.local/bin) |
curl -fsSL .../install.sh | sh -s -- --bin-dir /usr/local/bin
Only x86_64 is published for Linux today. On
aarch64 the script stops and points at the source
build rather than installing a binary that cannot run.
Piping a script into a shell runs code you have not read. The
script is install.sh at the root of the repository
— read it first if you would rather, then run it locally.
From source
fuzgit is not published to crates.io, so clone the repository and install from the local checkout.
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
macOS — Homebrew
brew install hatohato25/fuzgit/fuzgit
Linux / WSL — インストールスクリプト
curl -fsSL https://raw.githubusercontent.com/hatohato25/fuzgit/main/install.sh | sh
実行環境に合うリリース資産を取得し、SHA-256 チェックサムを検証した
うえで gz を ~/.local/bin へ配置します。
sudo は不要で、そのディレクトリの外には何も書きません。
PATH に無い場合は追加すべき行を表示するだけで、
シェルの設定ファイルは書き換えません。
| オプション | 環境変数 | 説明 |
|---|---|---|
--version <TAG> | FUZGIT_VERSION | 導入するリリース(既定は最新) |
--bin-dir <DIR> | FUZGIT_BIN_DIR | gz の配置先(既定は ~/.local/bin) |
curl -fsSL .../install.sh | sh -s -- --bin-dir /usr/local/bin
現在 Linux 向けに配布しているのは x86_64 のみです。
aarch64 では動かないバイナリを入れずに停止し、ソースからの
ビルドを案内します。
スクリプトをシェルへパイプするのは、読んでいないコードを実行することでも
あります。中身はリポジトリ直下の install.sh です。先に読んでから
手元で実行しても構いません。
ソースからインストール
crates.io へは未公開のため、リポジトリを取得してローカルからインストールします。
git clone https://github.com/hatohato25/fuzgit.git
cd fuzgit
cargo install --path .
~/.cargo/bin/gz がインストールされます(パッケージ名は
fuzgit、コマンド名は gz)。
インストールせずに試す場合:
cargo build --release
./target/release/gz --help
Usage使い方 #
gz <subcommand> [options]
Running gz with no arguments, or
gz --help, lists the subcommands.
引数なしの gz および gz --help で
サブコマンド一覧を表示します。
An option gets a short form only when git itself spells it
the same way — gz restore -S
(git restore -S), gz fetch -p
(git fetch -p), gz pull -r
(git pull -r), gz branch delete -f
(git branch -f) and so on. fuzgit-specific options are
long-only, and a letter git already uses for something else is
never reused: gz worktree add takes no short form
because git has no short spelling for it either.
オプションの短縮形は、git 本体に同じ意味の綴りがあるものだけに
付けています(gz restore -S =
git restore -S、gz fetch -p =
git fetch -p、gz pull -r =
git pull -r、gz branch delete -f =
git branch -f など)。fuzgit 固有のオプションは長い綴りだけとし、
git が別の意味で使っている文字は流用しません。gz worktree add に
短縮形が無いのは、git 側にも対応する綴りが無いからです。
| 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 (--action picks what to do next)
コミット履歴を辿り、フルハッシュを標準出力へ出す(--action で次の操作を選ぶ)
|
single単一 |
gz cherry-pick |
Pick commits and cherry-pick them コミットを選んで cherry-pick する | 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 変更を stash へ退避し、stash を検索して適用・破棄する | depends on subcommand サブコマンド次第 |
gz reflog |
Trace the HEAD reflog and recover lost commits (--action picks what to do next)
HEAD の reflog を辿り、失われたコミットを取り出す(--action で次の操作を選ぶ)
|
single単一 |
gz commit |
Pick changed files and commit only those 変更ファイルを選んで、選んだものだけをコミットする | multiple複数 |
gz fixup |
Pick the commit to amend and create a fixup commit 修正対象のコミットを選んで fixup コミットを作る | single単一 |
gz merge |
Pick the branch to merge (recovery menu while one is in progress) merge するブランチを選ぶ(進行中は復帰メニュー) | single単一 |
gz rebase |
Pick the base to rebase onto (recovery menu while one is in progress) rebase の base を選ぶ(進行中は復帰メニュー) | single単一 |
gz revert |
Pick the commits to undo and revert them 打ち消すコミットを選んで revert する | multiple複数 |
gz status |
List changed files and act on the ones you pick (two-step selection) 変更ファイルを一覧し、選んだファイルに操作を行う(2 段選択) | 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, in parallel; uses the network)
fetch の対象を決めて取得する(--siblings で隣のリポジトリも並列に一括取得。ネットワークを使う)
|
single / multiple with --siblings
単一/--siblings は複数
|
gz pull |
Pick branches and bring them up to their upstream in one go (fast-forward only; --rebase / --merge integrate the current branch instead; uses the network)
ブランチを選んで upstream へまとめて追随させる(fast-forward のみ。--rebase / --merge は現在のブランチが対象。ネットワークを使う)
|
multiple / none with --rebase複数/--rebase は選択なし |
gz worktree |
List and manage worktrees (add <name> creates one next to the repository)
worktree を一覧・管理する(add <name> はリポジトリの隣に作る)
|
single単一 |
gz pr |
Pick a GitHub pull request and check it out (--worktree <name> opens it in a review worktree; needs the gh CLI, uses the network)
GitHub の PR を選んで checkout する(--worktree <name> でレビュー用 worktree に開く。gh CLI が必要・ネットワークを使う)
|
single単一 |
Each command heading below carries chips for what the section contains. They describe the section as a whole — an option or a subcommand inside it, not necessarily the bare command.
- network talks to a remote.
- y/N asks before something you cannot take back.
- multi-select Tab picks more than one candidate.
以下の各コマンド見出しには、その節に何が含まれるかを示すチップを付けています。 対象は節全体であり、素のコマンドではなく中のオプション・サブコマンドを 指している場合もあります。
- 通信 リモートと通信します。
- y/N 取り消せない操作の前に確認します。
- 複数選択 Tab で複数の候補を選べます。
Status codes in file lists ファイル一覧の状態コード #
Every command that lists files —
gz restore,
gz add,
gz commit,
gz status — prefixes each
line with the same two status characters as
git status --short, in the same colours: green for
the index (staged) column, red for the working-tree column, and
red for both characters of an untracked file (??).
One thing differs: the two characters are
left-aligned. A change that exists only in the working
tree reads M where git writes
M. The column stays two characters wide, so the
paths still line up.
Because of that alignment, M means either a
staged change or an unstaged one, and only the colour
tells them apart. Without colour (NO_COLOR,
or output through a pipe) the two look identical.
ファイルを一覧するコマンド(gz restore・
gz add・gz commit・
gz status)は、行頭に
git status --short と同じ 2 文字の状態コードを、同じ配色で表示します
— index(staged)列は緑、作業ツリー列は赤、未追跡(??)は
2 文字とも赤です。
1 点だけ git と異なり、2 文字を左詰めで表示します。
作業ツリーだけの変更は、git の M ではなく
M になります。列幅は 2 文字のままなので、パスの開始位置は
揃います。
左詰めにしたため M は staged と unstaged のどちらでもあり得ます。
両者を区別するのは色だけです。NO_COLOR や
パイプ経由など色の付かない環境では、同じ見た目になります。
Language表示言語 #
Every piece of text fuzgit produces — messages, errors,
finder headers, confirmation prompts and --help
— is available in English and Japanese.
The language is detected from your locale, and
falls back to English whenever the locale is not
Japanese or cannot be interpreted. To pin it explicitly:
git config --global fuzgit.lang ja # persistent (--local sets it per repository; `en` pins English)
gz --lang ja branch # one-off, accepted by every subcommand
fuzgit が表示するすべての文言(メッセージ・エラー・finder のヘッダー・
確認プロンプト・--help)が日本語と英語に
対応しています。表示言語はロケールから自動的に決まり、
日本語ロケールでない場合や解釈できない場合は英語に
なります。明示的に固定するには次のように指定します。
git config --global fuzgit.lang ja # 永続設定(--local ならリポジトリごと。`en` なら英語に固定)
gz --lang ja branch # 単発の上書き。全サブコマンドで指定できる
| Priority優先 | Source取得元 | Meant for用途 |
|---|---|---|
| 1 | --lang <ja|en|auto> |
A one-off override. A global option, accepted by every subcommand; there is no short form. 単発の上書き。全サブコマンド共通のグローバルオプションで、短縮形はありません。 |
| 2 | FUZGIT_LANG |
Per shell or session. シェル・セッション単位の上書き。 |
| 3 | git config fuzgit.lang |
The persistent setting. system / global / local / worktree all apply exactly as they do for git itself. 永続設定。system / global / local / worktree の階層が git 本体と同じように効きます。 |
| 4 |
LC_ALL → LC_MESSAGES →
LANGUAGE → LANG
|
Read from the environment, in the POSIX and gettext order. 環境からの自動判定(POSIX / gettext と同じ順)。 |
| 5 | fallbackフォールバック | en |
-
Layers 1–3 are strict. They are explicit
instructions to fuzgit, so any value other than
ja,enorautostops with an error instead of quietly falling back. An empty value counts as “not set” and resolution moves to the next layer. If readingfuzgit.langfails altogether, fuzgit stops as well. -
Layer 4 is lenient. Locale variables describe
the environment rather than instruct fuzgit, so a value it
cannot interpret —
CandPOSIXincluded — is not an error; it simply means “not Japanese” and the fallback applies. -
automeans “skip the remaining explicit layers and read the environment”, wherever it appears in layers 1–3. -
There is no fuzgit configuration file. The
setting lives in git’s own
fuzgit.langkey, read in-process with gix — nogitprocess is started to resolve the language. -
The language resolves outside a repository too,
so
gz --helpand the “not a git repository” error are translated as well; system and global settings still apply there. One exception: afuzgit.langwritten under a conditional include (includeIf) in~/.gitconfigis not read when resolving outside a repository.
git’s own messages may stay English.
fuzgit tells every git command which language to speak, but
whether a catalog exists depends on how git was built (NLS) and
on the installed locale data — and
git upstream ships no Japanese catalog. Forcing
en is always safe: it just asks git for its
original text.
Text clap prints on its own stays English
— Usage:, Options:,
Commands: and parser errors, because clap 4 has no
localization hook. fuzgit’s own --help
descriptions do switch.
Output that fuzgit parses is a separate matter: those git
calls always run with LC_MESSAGES=C, whatever the
display language, so parsing never depends on the environment.
Debugging shows how the two are told apart in
the log.
-
層 1〜3 は厳格です。fuzgit への明示的な指定であるため、
ja/en/auto以外の値は 黙って既定へ倒さずエラーで停止します。空文字は「未設定」として扱い、 次の層へ進みます。fuzgit.langの読み取り自体に失敗した場合も 停止します。 -
層 4 は寛容です。ロケール環境変数は fuzgit への指示ではなく
環境の記述であるため、解釈できない値(
C/POSIXを 含む)はエラーにせず「日本語ではない」と判定してフォールバックへ進みます。 -
autoは層 1〜3 のどこに現れても「以降の明示指定を飛ばして 環境からの自動判定へ進む」という意味です。 -
fuzgit 独自の設定ファイルはありません。設定は git config の
fuzgit.langに置き、gix でプロセス内から読みます (言語の解決でgitプロセスは起動しません)。 -
言語はリポジトリの外でも解決できます。
gz --helpや「git リポジトリではありません」のエラーも 翻訳対象で、system / global の設定はそのまま効きます。ただし~/.gitconfigの条件付き include(includeIf)配下に 書いたfuzgit.langは、リポジトリ外での解決では読まれません。
git 本体のメッセージは英語のままになることがあります。
fuzgit は起動するすべての git へ言語を伝えますが、翻訳の有無は git の
ビルド(NLS)とロケールデータ次第です。とくに
git 本体には日本語カタログがありません。
en への統一は git に原文を出させるだけなので、環境に
依存せず成立します。
clap が自前で出す固定文言は英語のままです。
Usage: / Options: / Commands: と
パーサエラーが該当します(clap 4 に多言語化の機構がないため)。
--help のうち fuzgit 自身の文言は切り替わります。
fuzgit がパースする git の出力は別扱いで、表示言語に関わらず
常に LC_MESSAGES=C で実行します(環境によってパースが壊れない
ようにするため)。ログ上での見分け方は
デバッグを参照してください。
Configuration設定 #
fuzgit has no configuration file of its own. It borrows git’s config, so the usual system / global / local / worktree layers apply, and every key is optional.
fuzgit 独自の設定ファイルはありません。git config を 間借りするため、system / global / local / worktree の階層がそのまま効きます。 いずれのキーも任意です。
| git config keygit config キー | Value値 | Default既定 | What it does効果 |
|---|---|---|---|
fuzgit.lang |
ja / en / auto |
en |
Display language — see Language 表示言語 — 表示言語参照 |
fuzgit.notify |
boolean真偽値 | false |
Desktop notification when a long run finishes — see Completion notifications 長い実行の完了通知 — 完了通知参照 |
fuzgit.fetchJobs |
integer ≥ 11 以上の整数 | 4 |
How many repositories gz fetch --siblings fetches at once (1 is fully serial) — see gz fetch
gz fetch --siblings の同時実行数(1 で完全な直列)— gz fetch参照
|
| Environment variable環境変数 | What it does効果 |
|---|---|
FUZGIT_LANG |
Display language for one shell or session; beats fuzgit.lang, loses to --lang
シェル・セッション単位の表示言語。fuzgit.lang より優先し、--lang に劣後する
|
FUZGIT_DEBUG=1 |
Log every git command fuzgit runs — see Debugging fuzgit が実行した git コマンドをログへ出す — デバッグ参照 |
NO_COLOR |
Turn the colouring of gz fetch / gz pull / gz worktree add / gz branch off. Colour is only ever written to a terminal, and stdout and stderr are judged separately, so a pipe or a redirect is unaffected either way
gz fetch / gz pull / gz worktree add / gz branch の着色を止める。色は端末にしか書かず、標準出力と標準エラーは別々に判定するため、パイプ・リダイレクトでは元から影響しない
|
A value fuzgit cannot interpret is an error, not a silent
fallback to the default — a misspelled
fuzgit.fetchJobs stops before a single repository is
fetched. An empty value is the one exception: it
counts as “not set”.
解釈できない値は既定へ暗黙に倒さずエラーにします — 綴りを誤った
fuzgit.fetchJobs は 1 件も fetch しないまま停止します。
例外は空文字で、これは「未設定」として扱います。
gz branch — switch, create, delete and tidy up branches
gz branch — ブランチの切替・作成・削除・整理
y/Nmulti-select複数選択
#
gz branch # pick a local branch and run git switch (the classic behaviour)
gz branch --all # also list remote-tracking branches (origin/... and friends)
gz branch create <name> # pick the starting point and create a new branch
gz branch delete # pick branches and delete them
gz branch cleanup # delete every merged branch in one go
With no subcommand, gz branch switches
branches — that is the classic behaviour, and
--all only widens the candidate list.
create / delete / cleanup
are separate management operations. Mixing the two is ambiguous,
so clap rejects it: gz branch --all create x is an
error.
Switching (no subcommand)
| Option | Description |
|---|---|
-a, --all | Also list remote-tracking branches |
- The current branch is marked with a leading
*, just likegit branch. -
The preview opens with a summary of the highlighted branch
—
↑commits ahead of its upstream in green,↓commits behind in red, then the upstream, the last commit date and its author. A count of zero is left uncoloured, so only real drift catches the eye. Underneath are the 50 most recent commits (git log --oneline --decorate). A branch whose details cannot be read keeps the log and drops the summary. -
Picking a remote-tracking branch (
origin/feature) runsgit switchwith the short name (feature), so git’s DWIM creates the tracking local branch. -
git’s report after the switch is coloured.
Uncommitted changes carried across show their status letter in
colour —
Agreen,Myellow,Dred — while the path stays plain, andSwitched to branch 'x'is green.Already on 'x'and the tracking lines that follow are dimmed, since nothing happened there. git splits this report across both streams, so stdout and stderr are judged for colour separately:gz branch > fileleaves the file clean. SetNO_COLORto turn it off.
gz branch create <name> — creating a branch
| Argument / option | Description |
|---|---|
<NAME> | Name of the branch to create (required positional argument) |
--no-switch | Create the branch without switching to it |
-
What you pick is the starting point: local
branches, remote-tracking branches and tags. Each line is
prefixed with its kind (
[branch]in green,[tag]in yellow) because the two can share a name. -
It runs
git branch -- <name> <start point>, then switches to the new branch — the same asgit switch -c.--no-switchcreates it only, and prints the command to switch. -
The name is a positional argument, because skim
has no text input (see Out of scope).
Validation is git’s
check-ref-format; a name starting with-is protected with--and then rejected by git.
gz branch delete — deleting branches
| Option | Description |
|---|---|
-f, --force | Delete branches that are not merged either (git branch -D) |
--into <BRANCH> | Branch used as the merged/unmerged baseline (defaults to HEAD) |
- Candidates are local branches except the current branch and branches checked out in another worktree (git refuses to delete either).
-
A candidate line is
<name> merged|unmerged <relative update time> tracking: <upstream>|no tracking branch. Only information that can be gathered for every branch at once is put on the line; details of the last commit are in the preview (git log --oneline). - Tab selects several branches.
A confirmation prompt ([y/N]) lists every target
before anything runs. The default is
git branch -d, merged branches only:
one unmerged branch in the selection stops the whole
thing before git branch runs, so it never
deletes half the selection and then gives up. Only
--force switches to git branch -D, and
the prompt then names the unmerged branches you are about to
lose.
gz branch cleanup — deleting merged branches in one go
| Option | Description |
|---|---|
--into <BRANCH> | Branch used as the merged baseline (defaults to HEAD) |
- Candidates are limited to merged branches, and they start out selected — except the trunk (use Tab to select or deselect).
-
After the confirmation prompt they are deleted with
git branch -d. There is no--force— unmerged branches aregz branch delete --force’s job.
“Trunk” means the repository’s default branch
(whatever refs/remotes/<remote>/HEAD points
at) plus the conventional main and
master. --into defaults to
HEAD, so running this from a feature branch counts
its ancestor main as merged — preselected,
that would be two keystrokes from deleting your trunk. It stays
in the list with a label explaining why it is unselected, and
you can still select it deliberately.
gz branch # ローカルブランチから選んで git switch(従来どおりの切替)
gz branch --all # リモート追跡ブランチ(origin/... 等)も候補に含める
gz branch create <name> # 作成元を選んで新しいブランチを作る
gz branch delete # ブランチを選んで削除する
gz branch cleanup # merged なブランチを一括で削除する
サブコマンドなしの gz branch はブランチ切替です
(--all は候補の範囲を広げるだけ)。
create / delete / cleanup は別系統の
管理操作で、両者の併用は意図が曖昧になるため clap が拒否します
(gz branch --all create x はエラー)。
切替(サブコマンドなし)
| オプション | 説明 |
|---|---|
-a, --all | リモート追跡ブランチも候補に含める |
- 現在のブランチは
git branchと同じく行頭の*で識別できます。 -
プレビューの冒頭には選択中ブランチの要約を表示します。upstream より進んでいる
コミット数を
↑(緑)、遅れている数を↓(赤)で示し、 続けて upstream・最終コミット日時・作者が並びます。0 件の側には色を付けないため、 実際に差があるブランチだけが目に留まります。その下が直近 50 件のコミットログ (git log --oneline --decorate)です。要約を取得できなかった ブランチはログだけを表示します。 -
リモート追跡ブランチ(
origin/feature)を選ぶと短縮名(feature)でgit switchするため、git の DWIM により追跡ローカルブランチが作成されます。 -
切り替え後の git の報告に色が付きます。
持ち越した未コミットの変更は状態コードだけを着色し(
A緑、M黄、D赤)、パスは無色のままにします。Switched to branch 'x'は緑、Already on 'x'と後続の追跡状況の行は 何も起きていないため Dim にします。git はこの報告を 2 つのストリームへ 振り分けるため、標準出力と標準エラーの着色は別々に判定します (gz branch > fileのファイルに色は混ざりません)。NO_COLORで止められます。
gz branch create <name> — ブランチの作成
| 引数・オプション | 説明 |
|---|---|
<NAME> | 作成するブランチ名(必須の位置引数) |
--no-switch | 切り替えずに作成だけ行う |
-
選ぶのは作成元です。候補はローカルブランチ・リモート追跡
ブランチ・タグで、同名が共存しうるため行頭に種別が付きます
(ブランチは緑の
[branch]、タグは黄の[tag])。 -
実行するのは
git branch -- <name> <作成元>で、続けて 作成したブランチへ切り替えます(git switch -cと同じ)。--no-switchなら作成のみを行い、切り替えるコマンドを案内します。 annotated tag は解決済みの ID を渡し、git が対象コミットまで peel します。 -
名前は位置引数です(skim にテキスト入力 UI が無いため。
スコープ外・非対応参照)。妥当性検証は git の
check-ref-formatに委ね、-始まりの名前は--で保護したうえで git が拒否します。
gz branch delete — ブランチの削除
| オプション | 説明 |
|---|---|
-f, --force | merged でないブランチも削除する(git branch -D) |
--into <BRANCH> | merged 判定の基準ブランチ(既定は HEAD) |
- 候補はローカルブランチのうち、現在のブランチと、他の worktree で チェックアウト中のブランチを除いたものです(どちらも git が削除を許可しないため)。
-
候補行は
<名前> merged|unmerged <相対更新日時> 追跡: <upstream>|追跡なしです。 いずれも全件を一括取得できる情報に限っており、最終コミットの詳細はプレビュー (git log --oneline)で確認します。 - Tab で複数選択できます。
実行前に確認プロンプト([y/N])で対象を全件列挙します。既定は
git branch -d(merged のみ)で、unmerged が 1 件でも
含まれると git branch の実行前に停止します
(一部だけ削除して止まることはありません)。--force を
指定したときだけ git branch -D を使い、確認プロンプトが
失われる unmerged ブランチを名指しします。
gz branch cleanup — merged なブランチの一括削除
| オプション | 説明 |
|---|---|
--into <BRANCH> | merged 判定の基準ブランチ(既定は HEAD) |
- 候補を merged のブランチのみに絞り、幹を除いて選択済みの状態で 表示します(Tab で選択・解除できます)。
-
確認プロンプトを経て
git branch -dで一括削除します。--forceはありません(unmerged を扱うのはgz branch delete --forceの役目です)。
「幹」とはリポジトリの既定ブランチ
(refs/remotes/<remote>/HEAD が指す先)と、慣習的な
main / master です。--into の既定が
HEAD であるため、feature ブランチから実行すると祖先の
main も merged に該当します。選択済みのままでは 2 打鍵で幹が
消えてしまうため、事前選択から外しています。候補一覧には理由のラベル付きで
残るので、本当に消したい場合は自分で選択できます。
gz log — exploring the commit history
gz log — コミット履歴の探索
#
gz log # 1000 commits by default
gz log --limit 200 # limit how many commits are listed (-n also works)
git show "$(gz log)" # use the full hash of the picked commit directly
gz log --action # pick a commit, then pick what to do with it
| Option | Default | Description |
|---|---|---|
-n, --limit <N> | 1000 | Maximum number of commits to list |
--action | off | After picking a commit, show a menu of what to do with it |
- Each candidate is one line,
<short hash> <date> <summary> (<author>), and that whole string is what you filter on. - The preview is
git show --color=always(commit details and diff). -
On confirmation only the full hash of the picked
commit goes to stdout, for pipes and copying. Messages
go to stderr, so
$(gz log)is safe. -
--actionopens a second menu after the commit is picked: show the commit, switch to it as a detached HEAD, cherry-pick, revert, create a fixup commit, and print the full hash. The cherry-pick, revert, and fixup entries run the same code asgz cherry-pick/gz revert/gz fixup, so their safeguards still apply.
The default output is byte for byte what it has always been, so
git show "$(gz log)" keeps working. There is no
reset --hard entry in the menu: these commits are
ancestors of HEAD, and revert covers the
same need without discarding anything.
gz log # 既定 1000 件を候補にする
gz log --limit 200 # 取得件数を制限する(-n でも可)
git show "$(gz log)" # 選んだコミットのフルハッシュをそのまま使う
gz log --action # コミットを選んで、続けて行う操作も選ぶ
| オプション | 既定値 | 説明 |
|---|---|---|
-n, --limit <N> | 1000 | 取得するコミットの最大件数 |
--action | off | コミットを選んだあと、続けて行う操作をメニューから選ぶ |
- 候補は
<短縮ハッシュ> <日付> <サマリ> (<作者>)の 1 行で、この文字列がそのまま絞り込み対象です。 - プレビューは
git show --color=always(コミットの詳細と差分)。 -
決定すると選択コミットのフルハッシュだけを標準出力へ出します
(パイプ・コピー用途)。メッセージ類は標準エラーへ出すため、
$(gz log)で 安全に受け取れます。 -
--actionを付けると、コミットを選んだあとに 2 つ目のメニューが出ます — 詳細を表示する・detached HEAD で切り替える・ cherry-pick する・revert する・fixup コミットを作る・ フルハッシュを出力する。cherry-pick / revert / fixup はgz cherry-pick/gz revert/gz fixupと 同じ実装を呼ぶため、各コマンドの安全策がそのまま働きます。
既定の標準出力は従来と 1 バイトも変わらないため、
git show "$(gz log)" はそのまま動きます。メニューに
reset --hard はありません — gz log の候補は
HEAD の祖先であり、同じ用途は破棄を伴わない revert が
満たすためです。
gz cherry-pick — picking commits to cherry-pick
gz cherry-pick — cherry-pick するコミットの選択
multi-select複数選択
#
gz cherry-pick # commits from every branch
gz cherry-pick --branch feature # restrict to one branch
| Option | Description |
|---|---|
-b, --branch <BRANCH> | Target branch (without it, commits from all branches are listed) |
- Tab selects several commits. Whatever order you picked them in, they are always cherry-picked oldest first (history order).
- The candidate limit is 1000, the same as the default of
gz log --limit. -
On a conflict, git’s message is shown as-is and the exit
code is non-zero. Continue or abort with
git cherry-pick --continue/git cherry-pick --abort.
gz cherry-pick # 全ブランチのコミットを候補にする
gz cherry-pick --branch feature # 対象ブランチを指定する
| オプション | 説明 |
|---|---|
-b, --branch <BRANCH> | 対象ブランチ(未指定時は全ブランチのコミットを候補にする) |
- Tab で複数選択できます。選んだ順に関わらず、常に古い順(履歴順)に cherry-pick します。
- 候補件数の上限は
gz log --limitの既定値と同じ 1000 件です。 -
コンフリクト時は git のメッセージをそのまま表示して非ゼロ終了します。
続行・中止は
git cherry-pick --continue/git cherry-pick --abortで行ってください。
gz restore — picking files to restore or unstage
gz restore — 復元・アンステージするファイルの選択
y/Nmulti-select複数選択
#
gz restore # discard working tree changes (with confirmation)
gz restore --staged # unstage staged changes
gz restore --source HEAD~1 # overwrite with the content of a revision (with confirmation)
| Option | Description |
|---|---|
-s, --source <REV> | Revision to restore from; the file list of that commit becomes the candidate list |
-S, --staged | Unstage staged changes |
-
Tab selects several files. Candidates carry the same
status codes as
git status. They are left-aligned and coloured like git’s. - The preview is the diff of the file (with
--staged, the diff between HEAD and the index).
Anything that rewrites the working tree asks
[y/N] first, listing the files it is about to
overwrite. Unstaging with --staged touches only the
index, so it runs without a prompt.
gz restore # 作業ツリーの変更を破棄する(確認あり)
gz restore --staged # ステージ済みの変更をアンステージする
gz restore --source HEAD~1 # 指定リビジョンの内容で上書きする(確認あり)
| オプション | 説明 |
|---|---|
-s, --source <REV> | 復元元のリビジョン。指定するとそのコミットのファイル一覧が候補になる |
-S, --staged | ステージ済みの変更をアンステージする |
-
Tab で複数選択できます。候補には
git statusと 同じ状態コードが付きます。表示は git と同じ配色で左詰めです。 - プレビューは対象ファイルの差分(
--staged指定時は HEAD とインデックスの差分)。
作業ツリーを書き換える操作は、上書き対象を列挙したうえで
[y/N] を確認します。--staged による
アンステージはインデックスしか触らないため、確認せずに実行します。
gz add — picking files to stage
gz add — ステージするファイルの選択
multi-select複数選択
#
gz add
-
Candidates are unstaged changes and untracked files (files that
are already staged with no remaining difference do not appear),
each line prefixed with the same status code as
git status. They are left-aligned and coloured like git’s. - Tab selects several files.
- The preview is the diff for tracked files, and the file content (up to the first 64 KiB) for untracked files.
-
候補は未ステージの変更と未追跡ファイル(既にステージ済みで差分の無いファイルは
出ません)で、行頭には
git statusと同じ状態コードが付きます。表示は git と同じ配色で左詰めです。 - Tab で複数選択できます。
- プレビューは追跡ファイルは差分、未追跡ファイルはファイルの内容(先頭 64KiB まで)。
gz stash — creating, searching and restoring stashes
gz stash — stash の作成・検索・復元
y/Nmulti-select複数選択
#
push picks files;
apply / pop / drop pick an
existing stash. They are separate subcommands because
what you pick differs. Bare gz stash prints the
subcommand help rather than assuming one of them.
gz stash push # pick from the tracked changes and stash them
gz stash push -m "work in progress" # add a message
gz stash push -u # also list untracked files
gz stash apply # apply the picked stash (the stash stays)
gz stash pop # apply it and drop that stash
gz stash drop # discard the picked stash (with confirmation)
| Subcommand | Option | Description |
|---|---|---|
push | -m, --message <MESSAGE> | Message attached to the stash |
apply / pop / drop | (none) | Pick one entry from the stash list |
-
pushsupports multi-select with Tab, and only the files you picked are stashed (the rest stay in the working tree). Staged changes are stashed too, so the preview is the diff against HEAD (git diff HEAD). Files you have just created are listed as well — nogit addfirst. -
Candidates for
apply/pop/droparestash@{n}: <message>, so you can filter by message. The preview has two sections:files(which paths the stash holds and how much each changed) anddiffunderneath. Both ask git for--include-untracked, so a stash made only of brand-new files is not a blank pane.
drop discards a stash for good, so it asks
[y/N] first. pop drops the stash too,
but only after the apply succeeds.
push が選ぶのは「ファイル」、apply /
pop / drop が選ぶのは既存の「stash」です。
選択対象が異なるため、フラグではなくサブコマンドで分けています。
引数なしの gz stash は、どちらかへ暗黙に倒さずヘルプを表示します。
gz stash push # 追跡済みの変更から選んで退避する
gz stash push -m "作業中" # メッセージを付ける
gz stash push -u # 未追跡ファイルも候補に含める
gz stash apply # 選んだ stash を適用する(stash は残る)
gz stash pop # 適用して、その stash を取り除く
gz stash drop # 選んだ stash を破棄する(確認あり)
| サブコマンド | オプション | 説明 |
|---|---|---|
push | -m, --message <MESSAGE> | stash に付けるメッセージ |
apply / pop / drop | (なし) | stash 一覧から 1 件選ぶ |
-
pushは Tab で複数選択でき、選んだファイルだけが 退避されます(選ばなかった変更は作業ツリーに残ります)。ステージ済みの変更も 退避対象になるため、プレビューは HEAD との差分(git diff HEAD)です。 作ったばかりのファイルも候補に並びます(先にgit addする必要はありません)。 -
apply/pop/dropの候補はstash@{n}: <メッセージ>で、メッセージで絞り込めます。 プレビューは 2 段構成で、上にfiles(含まれるパスと変更量)、 下にdiffが出ます。どちらも--include-untracked付きで取るため、新規ファイルだけを 退避した stash でも空にはなりません。
drop は stash を完全に破棄するため、実行前に
[y/N] を確認します。pop も stash を取り除きますが、
適用が成功したあとに限られます。
gz reflog — investigating deleted branches
gz reflog — 削除済みブランチの調査
y/N
#
gz reflog # print the commit hash of the picked entry to stdout
gz reflog --restore recovered # create a new branch `recovered` from the picked commit
gz reflog --action # pick an entry, then pick what to do with it
| Option | Description |
|---|---|
--restore <NAME> | Create a new branch with the given name from the picked commit |
--action | After picking an entry, show a menu of what to do with it (cannot be combined with --restore) |
- Candidates are
<short hash> HEAD@{n}: <message>, so you can filter on messages such ascheckout: moving from .... -
By default only the full hash goes to stdout.
The result of
--restoregoes to stderr, leaving stdout free for pipes. -
--actionopens a second menu: show the commit, switch to it as a detached HEAD, cherry-pick, reset the current branch back to it, and print the full hash. -
--restoreis not deprecated, and the two flags cannot be combined: use--restorewhen the operation needs a name you have to type — a finder has no text input — and--actionfor everything else. -
An entry can point at an object
git gchas already removed. Those are listed on purpose; acting on one fails with git’s own message and a non-zero exit.
Reset the current branch back to it is the one
destructive entry in the --action menu. It asks for
an explicit y/N and runs no git at all if you
decline.
gz reflog # 選んだエントリのコミットハッシュを標準出力へ出す
gz reflog --restore recovered # 選んだコミットから新規ブランチ `recovered` を作成する
gz reflog --action # エントリを選んで、続けて行う操作も選ぶ
| オプション | 説明 |
|---|---|
--restore <NAME> | 選択したコミットから指定名の新規ブランチを作成する |
--action | エントリを選んだあと、続けて行う操作をメニューから選ぶ(--restore とは同時に指定できません) |
- 候補は
<短縮ハッシュ> HEAD@{n}: <メッセージ>で、checkout: moving from ...等のメッセージで絞り込めます。 -
既定ではフルハッシュだけを標準出力へ出します。
--restoreの 実行結果は標準エラーへ出るため、標準出力はパイプ用途のまま空けてあります。 -
--actionを付けると 2 つ目のメニューが出ます — 詳細を表示する・detached HEAD で切り替える・ cherry-pick する・現在のブランチをこのコミットへ戻す・ フルハッシュを出力する。 -
--restoreは非推奨ではありません(両者は同時に 指定できません)。finder にテキスト入力が無いため、入力が必要な名前を 渡すなら--restore、名前を要さない操作なら--actionと使い分けてください。 -
エントリは
git gcで実体を失っている場合があります(意図的に候補へ 出しています)。操作を実行すると git 自身のエラーがそのまま出て非ゼロ終了します。
--action のメニューで破壊的なのは
現在のブランチをこのコミットへ戻すだけです。実行前に
y/N の明示同意を求め、同意が得られなければ git を一切実行しません。
gz commit — picking the files to commit
gz commit — コミットするファイルの選択
multi-select複数選択
#
gz commit # commit only the files you picked (message via the editor)
gz commit -m "fix authentication" # give the message directly (no editor)
| Option | Description |
|---|---|
-m, --message <MESSAGE> | Commit message (without it, git opens the editor) |
-
Candidates are staged, unstaged and untracked changes in
one single list, each line prefixed with the same
status code as
git status. They are left-aligned and coloured like git’s. - Files with staged changes start out selected. Tab deselects them, and a deselected entry never comes back when you keep typing a filter.
-
It runs a path-limited commit,
git commit -- <paths>..., so changes you did not pick are not committed even if they were staged — they simply stay staged. Untracked files you picked aregit added first, since a path-limited commit cannot target them. -
The preview is the diff against HEAD, not against the index,
because that is what a path-limited commit records
(
git diff --color=always HEAD -- <path>; file content for untracked files). - With no changes at all it prints “There are no candidates to select from” and exits.
Without -m, the message is entered through
git commit — your core.editor.
A GUI editor configured without a wait flag exits
immediately, so git sees an empty message and aborts
with Aborting commit due to empty commit message.
Plain git commit behaves the same way.
git config --global core.editor "code --wait" # example for VS Code
-m sidesteps it entirely by never starting an
editor. fuzgit prints this hint to stderr when a commit fails.
gz commit # 選んだファイルだけをコミットする(メッセージはエディタで入力)
gz commit -m "認証を修正する" # メッセージを直接指定する(エディタを起動しない)
| オプション | 説明 |
|---|---|
-m, --message <MESSAGE> | コミットメッセージ(省略時は git がエディタを起動する) |
-
候補はステージ済み・未ステージ・未追跡の変更を1 つの一覧にしたもので、
行頭には
git statusと同じ状態コードが付きます。表示は git と同じ配色で左詰めです。 - ステージ済みの変更があるファイルは起動時から選択済みです。 Tab で選択を外せます(外した選択が絞り込みのたびに復活することはありません)。
-
実行するのは
git commit -- <paths>...のパス指定コミットです。 そのため選ばなかった変更はステージ済みであってもコミットされず、 ステージ状態のまま残ります。選んだ未追跡ファイルは、パス指定コミットの対象に できないため先にgit addします。 -
プレビューは index ではなく HEAD との差分です(パス指定コミットが記録するのは
作業ツリーの内容であるため。
git diff --color=always HEAD -- <path>。 未追跡ファイルは内容)。 - 変更が 1 件も無い場合は「選択できる候補がありません」と表示して終了します。
-m を省略すると、メッセージの入力は git commit
(= core.editor)に委ねられます。終了待ちなしで
GUI エディタを設定していると、エディタが即座に終了するため git は
メッセージが空だと判断し、
Aborting commit due to empty commit message. で中止されます
(素の git commit でも同じです)。
git config --global core.editor "code --wait" # VS Code の例
-m を指定すればエディタを起動しないため回避できます。
コミットが失敗したときは、この内容をヒントとして標準エラーへ表示します。
gz fixup — picking the target of a fixup commit
gz fixup — fixup コミットの対象選択
#
gz fixup # git commit --fixup=<picked commit>
gz fixup --squash # git commit --squash=<picked commit>
| Option | Description |
|---|---|
--squash | Create a squash commit (messages are combined) instead of a fixup commit |
-
What gets committed is the staged changes. With
nothing staged it exits before the finder even opens, telling
you to stage something with
gz addfirst. - Candidates are commits reachable from HEAD (1000 by default, shared with
gz log --limit). The preview isgit show --color=always. -
Afterwards the step that folds the commit into history is
printed to stderr. The rebase is never run for
you — rewriting history stays an explicit action.
For the very first commit there is noHint: run the following to fold the new commit into the history: git rebase -i --autosquash <full hash of the picked commit>^^to resolve, so the starting point becomes--root, with the reason printed alongside. --squashmakes git open the editor to append the message body (--fixupdoes not).
gz fixup # git commit --fixup=<選んだコミット>
gz fixup --squash # git commit --squash=<選んだコミット>
| オプション | 説明 |
|---|---|
--squash | fixup ではなく squash コミット(メッセージを結合する)を作成する |
- コミット対象はステージ済みの変更です。ステージ済みの変更が無い場合は、 finder を起動する前に「ステージ済みの変更がありません」と表示して終了します。
-
候補は HEAD からのコミット(既定 1000 件、
gz log --limitの既定値と共通)。 プレビューはgit show --color=always。 -
実行後、履歴へ取り込む手順を標準エラーへ表示します。
rebase は自動実行しません(履歴改変は明示操作に委ねます)。
最初のコミットには解決できるヒント: 作成したコミットを履歴へ取り込むには次を実行してください。 git rebase -i --autosquash <選んだコミットのフルハッシュ>^^が無いため、起点は--rootになります(理由も併記します)。 --squashは git がメッセージ本文の追記のためにエディタを起動します(--fixupは起動しません)。
gz merge — picking the branch to merge
gz merge — merge するブランチの選択
y/N
#
gz merge # a normal merge (fast-forwards when it can)
gz merge --no-ff # always create a merge commit
gz merge --squash # only apply the result to the working tree and index, without committing
gz merge --ff-only # merge only when it can fast-forward
| Option | Description |
|---|---|
--no-ff | Create a merge commit even when a fast-forward is possible |
--squash | Apply the merge result to the working tree and index without committing |
--ff-only | Merge only when a fast-forward is possible |
- The three options are mutually exclusive (combining them is rejected before the selection starts).
- The merge destination is fixed to the current position (
HEAD); candidates are local and remote-tracking branches excluding the current branch. - The preview is the commits that would be pulled in (
git log --oneline HEAD..<candidate>, up to 50). -
A confirmation prompt (
[y/N]) comes first, listing how many commits will be merged, the exact command that will run, and the conflict prediction. -
On a conflict, git’s message is shown as-is and the exit
code is non-zero. Resolve it with the
recovery menu (run
gz mergeagain) or with plain git.
It is a dry run of git merge-tree --write-tree and
needs Git 2.38 or newer. When it cannot be
produced the prompt says
“Conflict prediction: skipped”
and the merge still runs — “could not
predict” is never reported as “will not
conflict”.
gz merge # 通常の merge(fast-forward できる場合は fast-forward)
gz merge --no-ff # fast-forward できる場合でもマージコミットを作る
gz merge --squash # 結果を作業ツリー・index へ反映するだけでコミットしない
gz merge --ff-only # fast-forward できる場合のみ merge する
| オプション | 説明 |
|---|---|
--no-ff | fast-forward できる場合でもマージコミットを作成する |
--squash | マージ結果を作業ツリー・index へ反映するだけでコミットしない |
--ff-only | fast-forward できる場合のみ merge する |
- 3 つのオプションは相互排他です(同時に指定すると選択を始める前に拒否されます)。
- merge 先は現在の位置(
HEAD)に固定で、候補は現在のブランチを除くローカルブランチとリモート追跡ブランチです。 - プレビューは取り込まれるコミット(
git log --oneline HEAD..<候補>、最大 50 件)。 -
実行前に確認プロンプト(
[y/N])を表示します。 取り込まれるコミット数・実際に実行するコマンド・コンフリクト予測を提示します。 -
コンフリクトした場合は git のメッセージがそのまま表示され、非ゼロ終了します。
解決は復帰メニュー(
gz mergeを再実行)または 素の git で行います。
git merge-tree --write-tree のドライランであり、
Git 2.38 以降が必要です。予測できない場合は「省略しました」と
表示し、merge の実行は継続します。「予測できなかった」を
「コンフリクトしない」として扱うことはありません。
gz rebase — picking the rebase base
gz rebase — rebase の base の選択
y/N
#
gz rebase # pick the base and run git rebase <base>
- Candidates are local and remote-tracking branches excluding the current branch (tags and arbitrary commits are not offered).
- The preview is the commits that would be replayed (
git log --oneline <candidate>..HEAD, up to 50). - On a conflict, git’s message is shown as-is and the exit code is non-zero.
A confirmation prompt ([y/N]) comes first, stating
how many commits will be replayed and that their hashes will
change. Anyone who has already pulled those commits will have to
deal with the rewrite.
gz rebase # base を選んで git rebase <base>
- 候補は現在のブランチを除くローカルブランチとリモート追跡ブランチです(tag や任意コミットは候補に含めません)。
- プレビューは replay されるコミット(
git log --oneline <候補>..HEAD、最大 50 件)。 - コンフリクトした場合は git のメッセージがそのまま表示され、非ゼロ終了します。
実行前に確認プロンプト([y/N])を表示し、replay されるコミット数と
コミットハッシュが変わることを提示します。そのコミットを取得済みの相手には、
書き換えの影響が及びます。
The recovery menu for conflicts (gz merge / gz rebase / gz pull)
コンフリクト時の復帰メニュー(gz merge / gz rebase / gz pull)
y/N
#
Running gz merge / gz rebase /
gz pull while a merge or rebase
is in progress shows a recovery menu instead of the
usual flow. Its contents are decided by the operation that
is in progress (running gz merge during a
rebase shows the rebase menu).
| In progress | Menu entries |
|---|---|
| merge | Inspect the conflicted files and mark them resolved / resume the merge (git merge --continue) / abort the merge (git merge --abort) |
| rebase | Inspect the conflicted files and mark them resolved / resume the rebase (git rebase --continue) / skip the current commit (git rebase --skip) / abort the rebase (git rebase --abort) |
-
Whichever entry is highlighted, the preview shows the current
state (
git status --short --branch), so you can tell unresolved (UU) from resolved (M) on the spot. -
Choosing “inspect the conflicted files and mark them
resolved” lists the unmerged files. The preview shows
the diff including conflict markers
(
<<<<<<<and friends), and the files you pick with Tab aregit added (staged as resolved). Editing the files themselves is up to your own editor — fuzgit never launches one. - If you choose that entry with no unresolved files left, it tells you that you can resume with continue and exits.
- continue / skip run with inherited stdio, so git opens the editor when a commit message is needed.
- There is no recovery menu for cherry-pick or revert (that is left to git’s own
--continue/--abortguidance).
Aborting rolls the working tree back to before the merge or
rebase started, losing every conflict you have resolved since.
A confirmation prompt ([y/N]) comes first.
merge / rebase が進行中の状態で gz merge / gz rebase /
gz pull を実行すると、通常のフローではなく
復帰メニューが表示されます。メニューの内容は
進行中の操作の種類で決まります(rebase 進行中に
gz merge を実行しても rebase のメニューが出ます)。
| 進行中 | メニュー項目 |
|---|---|
| merge | コンフリクトファイルを確認して解決済みにする / merge を再開する(git merge --continue)/ merge を中止する(git merge --abort) |
| rebase | コンフリクトファイルを確認して解決済みにする / rebase を再開する(git rebase --continue)/ 現在のコミットを飛ばす(git rebase --skip)/ rebase を中止する(git rebase --abort) |
-
どの項目を選んでいても、プレビューには現在の状態
(
git status --short --branch)が出ます。未解決(UU等)と 解決済み(M)の区別をその場で確認できます。 -
「コンフリクトファイルを確認して解決済みにする」を選ぶと、コンフリクト中(unmerged)の
ファイル一覧が出ます。プレビューにはコンフリクトマーカー
(
<<<<<<<等)を含む差分が表示され、 Tab で選んだファイルをgit add(=解決済みとして stage)します。 ファイルの編集そのものは各自のエディタで行ってください(fuzgit はエディタを起動しません)。 - 未解決のファイルが 1 件も無い状態でこの項目を選んだ場合は、continue で再開できる旨を表示して終了します。
- continue / skip は継承 stdio で実行するため、コミットメッセージの入力が必要な場合は git がエディタを起動します。
- cherry-pick / revert には復帰メニューを用意していません(git の
--continue/--abortの案内に委ねます)。
中止(abort)は merge / rebase を始める前の状態まで戻すため、それまでに
解決したコンフリクトはすべて失われます。実行前に確認プロンプト
([y/N])を表示します。
gz revert — picking the commits to undo
gz revert — 打ち消すコミットの選択
multi-select複数選択
#
gz revert # revert the picked commits (message reviewed in the editor)
gz revert --no-edit # commit with git's default message, without opening the editor
| Option | Description |
|---|---|
--no-edit | Commit with git’s default message without opening the editor |
- Candidates are commits reachable from HEAD (1000 by default, shared with
gz log --limit). The preview isgit show --color=always. -
Tab selects several commits. Whatever
order you picked them in, they are reverted
newest first (undoing an old commit first tends
to clash with the later changes stacked on top of it —
exactly the opposite of
gz cherry-pick). - Picking several commits opens the editor once per commit unless you pass
--no-edit. -
On a conflict, git’s message is shown as-is and the exit
code is non-zero. Continue or abort with
git revert --continue/git revert --abort.
Reverting a merge commit needs
-m <parent-number>, and picking the mainline
is not something a fuzzy finder improves on. So a merge commit
in the selection stops fuzgit before
git revert runs — and it hands you a
ready-to-run git revert -m 1 <full hash>.
Merge commits are never silently dropped from the candidate
list.
gz revert # 選んだコミットを revert する(メッセージはエディタで確認)
gz revert --no-edit # エディタを起動せず git の既定メッセージのままコミットする
| オプション | 説明 |
|---|---|
--no-edit | エディタを起動せず、git の既定メッセージのままコミットする |
- 候補は HEAD からのコミット(既定 1000 件、
gz log --limitの既定値と共通)。プレビューはgit show --color=always。 -
Tab で複数選択できます。選んだ順に関わらず、常に新しい順に
revert します(古いコミットを先に打ち消すと、その上に積まれた後続の変更と衝突しやすいため。
gz cherry-pickの古い順とはちょうど逆になります)。 - 複数件を選ぶと
--no-editを付けない限りエディタが件数分だけ開きます。 -
コンフリクトした場合は git のメッセージをそのまま表示して非ゼロ終了します。
続行・中止は
git revert --continue/git revert --abortで行ってください。
マージコミットの revert には -m <parent-number> が必要ですが、
mainline の選択は「選ぶ」価値が乗らないため非対応です。選択に含まれる場合は
git revert を実行する前に停止し、
git revert -m 1 <フルハッシュ> の形でそのまま実行できる
コマンドを提示します(暗黙に候補から除外することはしません)。
gz status — the state dashboard (two-step selection)
gz status — 状態ダッシュボード(2 段選択)
multi-select複数選択
#
gz status
There are no options. It is a two-step flow: pick the files, then pick the action.
1. File selection (multi-select)
-
Candidates are staged, unstaged and untracked changes in one list
(the same candidate generation as
gz commit), each line prefixed with the same status code asgit status. They are left-aligned and coloured like git’s. -
The header summarises the current state in one line:
Without an upstream the whole ahead/behind block is omitted (on a detached HEAD,main | ahead 2 / behind 1 | staged 2 / unstaged 2 / untracked 1 / stash 1detached HEADis shown instead of the branch name). ahead/behind is computed from the local remote-tracking ref, so it uses no network. -
The preview is split into per-state sections:
staged(git diff --cached) when there are staged changes andunstaged(git diff) when there are unstaged ones; sections that do not apply do not run git at all. Untracked files show their content as-is.
2. Action menu (single select)
| Entry | What it runs |
|---|---|
| Stage the selected files (git add) | Same as gz add |
| Discard the changes of the selected files (git restore) | Same as gz restore (with a confirmation prompt) |
| Stash the selected files (git stash push) | Same as gz stash push (--include-untracked is added when untracked files were picked) |
| Commit the selected files (git commit) | Same as gz commit (untracked files are git added first; message via the editor) |
| Print the paths of the selected files to stdout | For pipes. Nothing but the paths is printed |
- Each action is literally the same implementation as the corresponding command, so its safeguards (restore’s confirmation prompt, commit’s pre-
addof untracked files) keep working. - The menu preview shows the current state (
git status --short --branch). - Every message except “print the paths to stdout” goes to stderr, so stdout stays free for pipes.
-
With no changes at all it is not an error: it exits with
code 0 (checking that the tree is clean is a legitimate
use of status). In that case the header-equivalent information
goes to stderr.
$ gz status There are no changes (the working tree is clean) main | staged 0 / unstaged 0 / untracked 0 / stash 0
オプションはありません。ファイルを選ぶ → アクションを選ぶの 2 段構成です。
1. ファイル選択(複数選択)
-
候補はステージ済み・未ステージ・未追跡の変更を 1 つの一覧にしたもの
(
gz commitと同じ候補生成)で、行頭にはgit statusと 同じ状態コードが付きます。表示は git と同じ配色で左詰めです。 -
ヘッダーに現在の状態を 1 行で表示します。
upstream が設定されていない場合、ahead / behind の区画ごと省略します (detached HEAD ではブランチ名の代わりにmain | ahead 2 / behind 1 | staged 2 / unstaged 2 / untracked 1 / stash 1detached HEADと表示します)。 ahead / behind はローカルのリモート追跡参照から算出するため ネットワークを使いません。 -
プレビューは状態別のセクションに分かれます。ステージ済みの変更があれば
staged(git diff --cached)、未ステージの変更があればunstaged(git diff)を表示し、該当しないセクションは git を実行しません。未追跡ファイルは内容をそのまま表示します。
2. アクションメニュー(単一選択)
| 項目 | 実行内容 |
|---|---|
| 選択したファイルをステージする (git add) | gz add と同じ |
| 選択したファイルの変更を破棄する (git restore) | gz restore と同じ(確認プロンプトあり) |
| 選択したファイルを stash へ退避する (git stash push) | gz stash push と同じ(未追跡を選んだ場合は --include-untracked が付く) |
| 選択したファイルをコミットする (git commit) | gz commit と同じ(未追跡ファイルは事前に git add、メッセージはエディタ) |
| 選択したファイルのパスを標準出力へ出力する | パイプ用途。パス以外は出力しない |
- 各アクションの実体は対応する既存コマンドと同じ実装であり、安全策 (restore の確認プロンプト、commit の未追跡ファイルの事前 add など)も そのまま働きます。
- メニューのプレビューには現在の状態(
git status --short --branch)を表示します。 - 「パスを標準出力へ出力する」以外のメッセージ類はすべて標準エラーへ出すため、標準出力はパイプ用途に空いています。
-
変更が 1 件も無い場合はエラーにせず、終了コード 0 で終わります
(クリーンな状態の確認も status の用途のため)。この場合はヘッダー相当の情報を
標準エラーへ出します。
$ gz status 変更はありません(作業ツリーはクリーンです) main | staged 0 / unstaged 0 / untracked 0 / stash 0
gz diff — pick what to compare and show the diff
gz diff — 比較対象を選んで差分表示
#
gz diff # unstaged changes (same as git diff)
gz diff --staged # staged changes (same as git diff --staged)
gz diff --head # HEAD against the working tree (including staged changes)
gz diff --upstream # HEAD against the upstream (the remote-tracking ref)
gz diff --branch # pick two branches and compare them
gz diff --commit # pick two commits and compare them
| Option | Description |
|---|---|
--staged | Target the staged changes (same as git diff --staged) |
--head | Compare HEAD with the working tree (including staged changes) |
--upstream | Compare HEAD with the upstream |
--branch | Pick two branches and compare them |
--commit | Pick two commits and compare them |
- The comparison modes are mutually exclusive. The flag names follow git’s own vocabulary.
-
--branch/--commitopen the fuzzy finder twice, for the left then the right side. The header tells you which one you are picking (1/2 branch to compare from, then2/2 branch to compare to). Candidates and previews are shared withgz branchandgz log. - Once the range is fixed, the list of changed files appears so you can narrow it down with Tab. The header shows the chosen range, and the preview is the coloured diff limited to the highlighted file.
-
On confirmation it runs
git diff <range> -- <pathspec>...with inherited stdio (pager and colour are left to git). Revision comparisons are passed as two arguments,git diff <a> <b>, not as<a>..<b>. -
--upstreamstops with a dedicated error when there is no upstream or on a detached HEAD. The right-hand side is the local remote-tracking ref (refs/remotes/<remote>/<branch>), so it uses no network. Rungz fetchfirst if you want to compare against the latest state. -
When the range contains no changed files it is not an
error: it exits with code 0.
$ gz diff There is no difference (Unstaged changes: index and work tree)
gz diff # 未ステージの変更(git diff と同じ)
gz diff --staged # ステージ済みの変更(git diff --staged と同じ)
gz diff --head # HEAD と作業ツリー(ステージ済みの変更も含む)
gz diff --upstream # HEAD と upstream(リモート追跡参照)
gz diff --branch # ブランチを 2 回選んで比較する
gz diff --commit # コミットを 2 回選んで比較する
| オプション | 説明 |
|---|---|
--staged | ステージ済みの変更を対象にする(git diff --staged と同じ) |
--head | HEAD と作業ツリーを比較する(ステージ済みの変更を含む) |
--upstream | HEAD と upstream を比較する |
--branch | ブランチを 2 回選択して比較する |
--commit | コミットを 2 回選択して比較する |
- 比較モードは相互排他です。フラグ名は git 本体の語彙に合わせています。
-
--branch/--commitは比較元・比較先の順に fuzzy finder を 2 回起動します。どちらを選んでいるかはヘッダー (1/2 比較元のブランチ/2/2 比較先のブランチ)で分かります。 候補・プレビューはそれぞれgz branch/gz logと共通です。 - 比較範囲が確定すると変更ファイル一覧が出るので、Tab で表示したいファイルを 絞り込めます。ヘッダーには確定した比較範囲を表示し、プレビューは選択中ファイルに 限定した色付き差分です。
-
決定すると
git diff <範囲> -- <pathspec>...を継承 stdio で 実行します(ページャ・色は git に委ねます)。リビジョン同士の比較は<a>..<b>ではなくgit diff <a> <b>の 2 引数で渡します。 -
--upstreamは upstream が設定されていない場合・detached HEAD の場合に 専用エラーで停止します。比較先はローカルのリモート追跡参照 (refs/remotes/<remote>/<branch>)であり、 ネットワークを使いません。最新の状態と比べたい場合は先にgz fetchを実行してください。 -
比較範囲に変更ファイルが 1 件も無い場合はエラーにせず、終了コード 0 で終わります。
$ gz diff 差分はありません(未ステージの変更: index と作業ツリー)
gz fetch — deciding what to fetch
gz fetch — fetch 対象の取得
network通信multi-select複数選択
#
gz fetch # decide what (which remote) to fetch and run git fetch
gz fetch --prune # also clean up tracking refs for branches deleted on the remote
gz fetch --siblings # pick repositories sitting next to this one and fetch them all
| Option | Description |
|---|---|
-p, --prune | Delete tracking refs for branches deleted on the remote (git fetch --prune) |
-s, --siblings | Also target repositories sitting at the same level as the current one (multi-select) |
The point of this command is not “pick a remote” but “decide what to fetch”. The fuzzy finder only opens when there is actually a choice.
Default (the current repository)
-
The finder only opens when there is more than one
remote. Candidates are the registered remote names plus
a fixed entry, all remotes, which
runs
git fetch --all. -
With exactly one remote the finder does not open and the
fetch runs immediately, because choosing between the only
remote and “all remotes” would contact the same place
either way. So that you can still tell what was contacted, one
line naming the target is printed to stderr before running
(
git fetchcan print nothing at all when there are no updates).$ gz fetch Fetching from the remote `origin` (only one remote is registered, so the selection was skipped) - The preview only shows local information (two sections: the remote URL and the known remote-tracking branches). A remote that has never been fetched has no tracking refs, so that section is omitted entirely. Not using the network in previews is a design rule — see Network operations.
- With no remotes registered at all it suggests
git remote addand exits.
--siblings — fetching the repositories next door
Every other fuzgit command touches only the current
repository. --siblings is the single
exception. Given the flag, it scans the parent directory
of the current worktree root, one level deep (never
recursively) and offers the directories that contain a
.git.
$ 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
The candidate list
-
A line is
<directory name> <remote>/<current branch>, one pair per remote. A repository whose HEAD points at no branch reads<directory name> <remotes> detached HEADinstead. Columns are padded to the widest value, so the next column starts in the same place on every line. - The current repository starts selected (Tab deselects it); the others start unselected.
- No remote registered and bare repositories cannot be fetched, so they are excluded — and the header says how many, never silently.
- Linked worktrees of one repository are deduplicated into a single entry, so the same remote is not contacted twice. Symlinked directories are not followed.
-
When the current repository is the only target the
finder does not open. The reason is printed and the
fetch runs.
$ gz fetch --siblings The current repository is the only target, so the selection was skipped [1/1] only 1 succeeded / 0 failed -
The preview is local information only: each
remote’s URL, and each local branch’s tracking state
from
git for-each-ref refs/heads. It runs with--no-optional-locks, so it never takes a lock in somebody else’s repository.── origin ── git@github.com:example/big-repo.git ── Branch tracking status ── develop → origin/develop [ahead 2] * main → origin/main [behind 4]
On a terminal, the lines fuzgit writes itself are coloured so
they stand out from git’s own output: the
[n/N] progress lines are cyan (a colour git does
not use), and the closing summary is green, or red as soon as
one target failed. In git’s update table the status code
is coloured too — green for a new branch, yellow for a
tag, red for a deletion, a forced update or a rejection —
while a plain fast-forward, the ordinary result, is left alone.
Only the status code is painted, never the reference names.
Set NO_COLOR to turn this off; output to a pipe or
a file is never coloured to begin with.
git status walks the whole working tree before
printing anything, which can take seconds per preview in a large
repository and would stall every cursor move. The ahead/behind
you actually need to decide about a fetch is in the tracking
state above. Anything else that would cost one git
process per repository is kept out of the list for the same
reason — the first paint stays fast.
The run
-
Each repository runs
git fetch [--prune] --all, in parallel. Output is captured and written out as one block per repository when it finishes, headed by[<done>/<total>] <directory name>, so update tables never interleave. -
How many run at once comes from
git config fuzgit.fetchJobs— an integer of 1 or more, 4 when unset, and1for the fully serial behaviour. An invalid value stops the run before anything is fetched instead of quietly falling back. There is no CLI flag for it.git config fuzgit.fetchJobs 8 # or --global -
--pruneapplies to every selected repository. The finder header says so. -
git config fuzgit.notify trueposts a desktop notification when the run finishes (see Completion notifications). -
A failing repository does not stop the run. The
rest still execute, and the summary at the end names the ones
that failed. If even one fails the exit code is
1; git has already shown the reason, so fuzgit
does not repeat it.
$ gz fetch --siblings [1/3] mike [2/3] alpha [3/3] zulu fatal: '/path/to/does-not-exist.git' does not appear to be a git repository fatal: Could not read from remote repository. 2 succeeded / 1 failed (failed: zulu) error: Fetching failed for some repositories -
If launching
gititself fails (git not installed, say) the run stops there — that is an environment problem, not a per-repository failure. -
With nothing fetchable at all it stops with a dedicated error.
So does a bare current repository, or one whose worktree root has
no parent directory to scan. It never falls back to
just the current repository, so the range you asked for
and the place it contacts can never diverge.
$ gz fetch --siblings error: There is no repository to fetch (a repository without a remote and a bare repository are not offered)
No password, passphrase or host-key prompt can reach you while several fetches share the terminal. Any repository that fails there is run again, once, one at a time, with the terminal attached so you can answer. That second run is not a retry — it only changes how the command is run.
The parallel phase overrides core.sshCommand with
an environment variable, and an environment variable beats the
config key (see man git-config). Every target then
fails in parallel and falls through to the serial pass. The
result is still correct; you simply do not get the speedup.
Common to both
git fetchruns with inherited stdio, so the list of updated refs, authentication prompts and progress output are git’s own.- Network and authentication failures are shown with git’s message as-is and exit non-zero (fuzgit adds no timeout and no retry).
gz fetch # fetch 対象(リモート)を決めて git fetch する
gz fetch --prune # リモートで削除されたブランチの追跡参照も掃除する
gz fetch --siblings # 隣に並ぶリポジトリを選んでまとめて fetch する
| オプション | 説明 |
|---|---|
-p, --prune | リモートで削除されたブランチの追跡参照を削除する(git fetch --prune) |
-s, --siblings | 現在のリポジトリと同じ階層に並ぶリポジトリも対象に含める(複数選択) |
このコマンドの主機能は「リモートを選ぶ」ことではなく 「fetch 対象の決定」です。 選択の余地がある場合にだけ fuzzy finder を起動します。
既定(現在のリポジトリ)
-
リモートが複数ある場合だけ finder を起動します。候補は登録済みの
リモート名に、固定候補「すべてのリモート」を加えたものです。「すべてのリモート」を
選ぶと
git fetch --allを実行します。 -
リモートが 1 つだけの場合は finder を起動せず、そのまま fetch します。
唯一のリモートと「すべてのリモート」の 2 択は、どちらを選んでも通信先が同じためです。
何に対して通信したのかが分かるよう、実行前に対象を 1 行だけ標準エラーへ示します
(
git fetchは更新が無ければ何も出力しないことがあるため)。$ gz fetch リモート `origin` から取得します(登録されているリモートが 1 つのため、選択を省略しました) - プレビューはローカル情報だけを表示します (「リモート URL」と「既知のリモート追跡ブランチ」の 2 セクション)。一度も fetch して いないリモートは追跡参照が無いため、そのセクションごと省略されます。 プレビューでネットワークを使わないのは設計上の原則です (ネットワーク操作について参照)。
- リモートが 1 つも登録されていない場合は
git remote addを促して終了します。
--siblings — 隣のリポジトリもまとめて取得
fuzgit の他のコマンドは現在のリポジトリだけを操作します。
--siblings はその唯一の例外で、フラグを明示したときに限り、
ワークツリー root の親ディレクトリ直下のみを走査し(再帰しません)、
.git を持つディレクトリを候補にします。
$ gz fetch --siblings
現在のリポジトリを選択済みにしています。Tab: 選択の切替 / Enter: 取得 | 除外 1 件(リモート未登録 / bare)
>> mike origin/main
alpha origin/main
zulu origin/main
候補一覧
-
候補行は
ディレクトリ名 リモート/現在のブランチで、リモートの数だけ 並びます。HEAD がブランチを指していないリポジトリはディレクトリ名 リモート detached HEADと表示します。各列は一覧中で 最も長い値に合わせて空白で埋めるため、右の列の開始位置はすべての行で揃います。 - 現在のリポジトリは起動時から選択済みです (Tab で外せます)。他は未選択です。
- リモート未登録のリポジトリと bare リポジトリは fetch できないため除外し、除外件数をヘッダーに示します(黙って消しません)。
- 同じリポジトリの linked worktree が隣に並んでいる場合は1 件に重複排除します (同じリモートへ二重に通信しないため)。シンボリックリンクのディレクトリは辿りません。
-
対象が現在のリポジトリ 1 件だけの場合は finder を起動せず、
理由を示してそのまま実行します。
$ gz fetch --siblings 対象が現在のリポジトリ 1 件のため、選択を省略しました [1/1] only 成功 1 件 / 失敗 0 件 -
プレビューはローカル情報だけです(リモートごとの URL と、
git for-each-ref refs/headsによるローカルブランチごとの追跡状況)。 他人のリポジトリでロックを取らないよう--no-optional-locksを付けます。── origin ── git@github.com:example/big-repo.git ── ブランチの追跡状況 ── develop → origin/develop [ahead 2] * main → origin/main [behind 4]
端末では、fuzgit 自身が出す行に色が付き、git の出力と見分けられます。
[n/N] の進捗行はシアン(git が使わない色)、末尾の集計行は
成功なら緑、1 件でも失敗すれば赤になります。git の更新表も状態コードだけ
着色し、新しいブランチは緑、タグは黄、削除・強制更新・拒否は赤、
通常の結果である早送りの更新は無色のままにします。色を乗せるのは
状態コードだけで、参照名には乗せません。
NO_COLOR を設定すると止められます。パイプやファイルへの
出力は元から着色されません。
git status は結果を出す前に作業ツリー全体を走査するため、
ファイル数の多いリポジトリではプレビュー 1 件に数秒掛かり、カーソルを
動かすたびに待たされます。fetch の判断に必要な ahead / behind は上記の
追跡状況で分かります。1 リポジトリあたり git の起動が必要な情報を候補一覧に
載せないのも同じ理由です(初期表示を速く保つため)。
実行
-
各リポジトリで
git fetch [--prune] --allを並列に 実行します。出力はキャプチャし、完了した順に[<完了件数>/<全体>] <ディレクトリ名>を頭に付けて ひとまとまりで書き出すため、複数リポジトリの更新表が混ざりません。 -
同時実行数は
git config fuzgit.fetchJobsで決まります (1 以上の整数。未設定なら 4、1で完全な直列実行)。 不正な値のときは既定値へ暗黙に倒さず、1 件も fetch しないまま停止 します。CLI のフラグは設けていません。git config fuzgit.fetchJobs 8 # --global も可 -
--pruneは選択したすべてのリポジトリに適用されます (その旨は finder のヘッダーに表示します)。 -
git config fuzgit.notify trueを設定すると、 完了をデスクトップ通知で知らせます (完了通知参照)。 -
途中で失敗しても中断せず残りを実行し、最後に成功・失敗件数と
失敗したリポジトリ名を集計します。1 件でも失敗すれば終了コード 1
です(失敗理由は git が表示済みのため再掲しません)。
$ gz fetch --siblings [1/3] mike [2/3] alpha [3/3] zulu fatal: '/path/to/does-not-exist.git' does not appear to be a git repository fatal: Could not read from remote repository. 成功 2 件 / 失敗 1 件(失敗: zulu) エラー: 一部のリポジトリで取得に失敗しました -
gitの起動そのものに失敗した場合(git 未インストール等)は その場で中断します。環境の問題であり、リポジトリごとの失敗ではないためです。 -
fetch できるリポジトリが 1 件も無い場合、現在のリポジトリが bare の場合、
ワークツリー root の親ディレクトリを取得できない場合は、いずれも専用エラーで
停止します。暗黙に現在のリポジトリだけへ倒すことはしません
(指定した範囲と通信先が食い違わないようにするため)。
$ gz fetch --siblings エラー: fetch できるリポジトリがありません(リモートが登録されていないリポジトリと bare リポジトリは対象になりません)
複数の fetch が端末を共有するため、パスワード・passphrase・ホスト鍵の確認は 届きません。そこで失敗したリポジトリだけを、端末をつないだまま 1 件ずつ実行し直します。これはリトライではなく 実行方法の切り替えであり、1 回だけ行います。
並列フェーズは core.sshCommand を環境変数で上書きし、環境変数は
config より優先されます(man git-config)。そのため対象がすべて
並列フェーズで失敗し、直列フェーズへ回ります。結果は正しく得られますが、
高速化の恩恵は受けられません。
共通
git fetchは継承 stdio で実行するため、更新された参照の一覧・認証プロンプト・進捗表示は git のものがそのまま出ます。- ネットワーク・認証の失敗は git のメッセージをそのまま表示して非ゼロ終了します(fuzgit 側でのタイムアウト・リトライは行いません)。
gz pull — bringing several branches up to date
gz pull — 複数ブランチの一括取り込み
network通信y/Nmulti-select複数選択
#
gz pull # pick branches and fast-forward them onto their upstream
gz pull --rebase # rebase the current branch onto its upstream
gz pull --merge # merge the upstream into the current branch
| Option | Description |
|---|---|
-r, --rebase | Integrate the current branch by rebasing onto its upstream (rewrites history) |
--merge | Integrate the current branch by merging its upstream |
Without a flag, the only thing you pick is
which branches should follow their upstream —
several local branches of the current repository. You never pick a
remote × branch combination, because the destination is fixed
to each branch’s own upstream. There is no
--prune and no positional branch name.
--rebase and --merge are a different
shape entirely; see
Two shapes below.
-
Candidates are local branches that have an upstream whose
branch.<name>.remoteis a registered remote name. Branches without an upstream, with an unregistered remote, or checked out in another worktree have no determinable destination, so they are excluded — and the number excluded is shown in the header (never dropped silently). -
The current branch is put first, marked with a leading
*(as ingz branch), and starts selected (Tab deselects it). On a detached HEAD there is simply no current branch, and the other branches are offered as usual (unlikegz pull --rebase/--merge, this is not an error).$ 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 -
A candidate line is
<mark><branch> → <short upstream name>. ahead / behind is deliberately not shown: at that moment fuzgit only knows the last fetch’s tracking refs, which is not how much is about to arrive, and a stale “not behind” would mislead. The real figure appears in git’s own update table at run time. -
The preview is headed
── Commits not integrated yet (as of the last fetch) ──and shows the commits between the branch and its locally stored tracking ref (git log --oneline <branch>..<tracking ref>). The heading states that the information is as of the last fetch: the preview uses no network (see Network operations). -
With only one candidate the finder does not open;
the target and the reason are printed in one line and the run
starts.
$ gz pull Integrating `main` (there is only one candidate, so the selection was skipped) [1/1] main 1 succeeded / 0 failed -
With no candidates at all it stops and explains how to set an
upstream (
git push -u <remote> <branch>/git branch --set-upstream-to=<remote>/<branch>). -
Execution starts with
git fetch <remote>once per remote that the selected upstreams belong to (never once per branch). If one remote fails to fetch, every branch whose upstream lives on that remote is recorded as failed and skipped, while branches on other remotes continue — so nothing is ever integrated implicitly from a stale tracking ref. -
Integration then happens one branch at a time, serially,
in candidate order (never in parallel). Before each one,
[<n>/<total>] <branch>is printed to stderr (same format asgz fetch --siblings), because git’s update tables and rejection reasons also go to stderr. -
The currently checked out branch is integrated with
git merge --ff-only <tracking ref>(the working tree and index have to be updated), while every other branch usesgit fetch . <tracking ref>:refs/heads/<branch>(updating only the ref, never touching the working tree). The latter refspec deliberately omits the forcing+: with it, non-fast-forward updates would go through and commits that exist only on that branch would be lost. -
A failing branch does not stop the run; the rest
still execute and successes, failures and the failed branch names
are summarised at the end. If even one fails the exit code is
1 (git already printed the reason, so fuzgit does
not repeat it). Only when at least one branch could not
fast-forward is a one-line pointer to the next step added.
It only points at it — a rebase or merge is never started automatically. How history is integrated (rebase or merge) stays an explicit user choice.$ 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 pull --rebase` or `gz pull --merge` after switching to it error: Integrating failed for some branches - If launching
gititself fails (git not installed, for example) the run stops there, because that is an environment problem rather than a per-branch failure. -
No
[y/N]prompt in this shape. Multi-selecting and pressing Enter is already an explicit decision, and a fast-forward loses neither existing commits nor working tree changes — the same judgement asgz fetch --siblings.--rebase/--mergedo confirm. - Run while a merge or rebase is in progress, it shows the recovery menu instead of the branch selection.
“Get back to the state before the pull if something goes wrong” is met not by a rollback routine but by never running an operation that can break anything. A fast-forward does not recreate existing commits, and git refuses without changing anything when it cannot fast-forward, when the change would clash with the working tree, or when the branch is in use by another worktree. A failure therefore leaves the pre-pull state intact, and there is nothing to roll back.
The alternatives were rejected for the same reason:
git merge --abort cannot always reconstruct the
original state when there are uncommitted changes, and
git reset --hard discards them outright.
Two shapes: fast-forward in bulk, or one branch your way
| Aspect | gz pull | gz pull --rebase / --merge |
|---|---|---|
| Target | Several local branches that you pick | The current branch only (fixed to its upstream) |
| Integration | Fast-forward only | Rebase onto, or merge, the upstream |
| Selection UI | Multi-select of branches | None — there is nothing to pick |
| Confirmation prompt | No | Yes |
A branch that plain gz pull could not fast-forward is
integrated by switching to it and running
gz pull --rebase or gz pull --merge.
The reason --rebase / --merge cover only
the current branch is mechanical: a branch that is not checked out
can be moved along by copying a ref
(git fetch . <tracking>:refs/heads/<branch>),
which is fast-forward by definition. Rebasing or merging it would
mean switching the working tree, or creating a temporary worktree
— both of which put work you have in progress at risk.
These two flags used to be a separate command,
gz sync. It was folded in here so that
“bring changes in” is one command rather than two.
gz pull # 取り込むブランチを選んで、upstream へ fast-forward で追随させる
gz pull --rebase # 現在のブランチを upstream へ rebase して取り込む
gz pull --merge # 現在のブランチへ upstream を merge して取り込む
| オプション | 説明 |
|---|---|
-r, --rebase | 現在のブランチを upstream へ rebase して取り込む(履歴を書き換える) |
--merge | 現在のブランチへ upstream を merge して取り込む |
フラグ無しで選ばせるのは「どのブランチを upstream へ追随させるか」だけ
です。対象は現在のリポジトリの複数のローカルブランチで、リモート × ブランチの
組み合わせは選ばせません(追随先は各ブランチの upstream に固定)。
--prune やブランチ名の位置引数はありません。
--rebase / --merge は形そのものが異なります —
下の2 つの形を参照してください。
-
候補は upstream が設定され、その
branch.<name>.remoteが 登録済みのリモート名であるローカルブランチです。upstream が無いもの・ リモートが登録されていないもの・他の worktree でチェックアウト中のものは 取り込み先を決められないため候補から除外し、除外した件数をヘッダーに 示します(黙って消しません)。 -
現在のブランチは一覧の先頭に置き、行頭を
*(gz branchと同じ)でマークして、起動時から選択済みにします (Tab で外せます)。detached HEAD の場合は現在のブランチが無いだけで、 他のブランチは通常どおり候補になります(gz pull --rebase/--mergeと 違いエラーにはしません)。$ gz pull 現在のブランチを選択済みにしています。Tab: 選択の切替 / Enter: fast-forward のみで取り込み | 除外 2 件(upstream 未設定 / リモート未登録 / 他の worktree で使用中) >> * main → origin/main feature-a → origin/feature-a -
候補行は
<マーク><ブランチ名> → <upstream の短縮名>です。 ahead / behind は意図的に表示しません。この時点で分かるのは 前回 fetch した追跡参照との差であり、これから取り込む本数とは一致せず、 古い「遅れていない」は誤解を招くためです。実際の本数は実行時に git 自身が出す 更新表で分かります。 -
プレビューは
── 未取り込みのコミット(前回の fetch 時点) ──の見出しを 付けて、ローカルに保存済みの追跡参照との差分コミット (git log --oneline <ブランチ>..<追跡参照>)を表示します。 それが前回の fetch 時点の情報であることを見出しで示しており、 プレビューではネットワークを使いません(ネットワーク操作について参照)。 -
候補が 1 件だけの場合は finder を起動せず、対象と省略の理由を
1 行示してそのまま実行します。
$ gz pull `main` を取り込みます(候補が 1 件のため、選択を省略しました) [1/1] main 成功 1 件 / 失敗 0 件 -
候補が 1 件も無い場合は、upstream の設定方法(
git push -u <remote> <branch>/git branch --set-upstream-to=<remote>/<branch>)を案内して停止します。 -
実行はまず、選択したブランチの upstream が属するリモートごとに 1 回だけ
git fetch <remote>します(ブランチごとに通信しません)。 あるリモートの取得に失敗した場合は、そのリモートを upstream に持つブランチをすべて 失敗として記録して飛ばし、他のリモートのブランチは続行します(古い追跡参照のまま 暗黙に取り込まないためです)。 -
取り込みは候補一覧の順序で 1 ブランチずつ直列に実行します
(並列にしません)。実行前に
[<何番目>/<全体>] <ブランチ名>を 標準エラーへ表示します(gz fetch --siblingsと同形式)。git 自身の更新表や 拒否の理由も標準エラーに出るため、この 1 行が無いとどのブランチの出力なのか 読み取れなくなります。 -
現在チェックアウト中のブランチは
git merge --ff-only <追跡参照>(作業ツリーと index を 更新する必要があるため)、それ以外のブランチはgit fetch . <追跡参照>:refs/heads/<ブランチ>(参照だけを更新し作業ツリーに触れない)で取り込みます。後者の refspec に強制更新の+は付けません。付けると非 fast-forward の更新が通り、 そのブランチにしか無いコミットを失わせるためです。 -
途中のブランチが失敗しても中断せず残りを実行し、最後に成功件数・
失敗件数と失敗したブランチ名を集計表示します。1 件でも失敗した場合は
終了コード 1 で終わります(失敗理由は git のメッセージがその場で
表示済みのため、fuzgit は再掲しません)。fast-forward できなかったブランチが
1 件以上あるときだけ、次の手段を 1 行案内します。
案内するだけで、rebase や merge を自動で始めることはありません。 履歴の統合方法(rebase か merge か)はユーザーの明示指定に限ります。$ gz pull [1/4] main [2/4] alpha [3/4] diverged [4/4] zeta 成功 3 件 / 失敗 1 件(失敗: diverged) fast-forward できなかったブランチは、そのブランチへ切り替えてから `gz pull --rebase` または `gz pull --merge` で取り込めます エラー: 一部のブランチで取り込みに失敗しました -
gitの起動そのものに失敗した場合(git 未インストール等)は、 その場で中断します。環境の問題でありブランチごとの失敗ではないためです。 -
この形では
[y/N]の確認プロンプトはありません。 複数選択して Enter を押すこと自体が明示的な決定であり、fast-forward は 既存のコミットも作業ツリーの変更も失わせないためです (gz fetch --siblingsと同じ判断)。--rebase/--mergeでは確認します。 - merge / rebase が進行中の状態で実行した場合は、ブランチ選択ではなく 復帰メニューが表示されます。
「何かあれば pull 前の状態に戻す」ことを、ロールバック処理ではなく 壊し得る操作を行わないことで満たすためです。fast-forward は 既存のコミットを作り直さず、fast-forward できない場合・作業ツリーの変更と 衝突する場合・他の worktree で使用中の場合は、いずれも git が 何も変更せずに拒否します。そのため失敗しても取り込み前の状態が そのまま残り、巻き戻す対象がありません。
代替案を採らなかった理由も同じです。git merge --abort は未コミットの
変更があると元の状態を再構成できないことがあり、git reset --hard は
未コミットの変更を破棄します。
2 つの形 — まとめて fast-forward か、1 本を方式を選んで取り込むか
| 観点 | gz pull | gz pull --rebase / --merge |
|---|---|---|
| 対象 | 選んだ複数のローカルブランチ | 現在のブランチのみ(upstream に固定) |
| 取り込み方式 | fast-forward のみ | upstream へ rebase、または merge |
| 選択 UI | ブランチの複数選択 | 無し — 選ぶものが無いため |
| 確認プロンプト | 無し | あり |
フラグ無しの gz pull で fast-forward できなかったブランチは、
そのブランチへ切り替えてから gz pull --rebase または
gz pull --merge で取り込みます。
--rebase / --merge が現在のブランチだけを対象に
するのは機構上の理由です。チェックアウトしていないブランチは参照のコピー
(git fetch . <tracking>:refs/heads/<branch>)でしか
追随させられず、これは定義上 fast-forward です。rebase や merge を行うには
作業ツリーを切り替えるか一時 worktree を作る必要があり、いずれも進行中の作業を
危険に晒します。
この 2 つのフラグは、以前は gz sync という独立したコマンドでした。
「取り込む」操作を 2 つのコマンドに分けると使い分けが読み取れないため、
こちらへ畳んで 1 つにまとめています。
gz worktree — listing and managing worktrees
gz worktree — worktree の一覧・管理
y/N
#
gz worktree # pick from the list and print the path to stdout
cd "$(gz worktree)" # shell integration (move to the picked worktree)
gz worktree add <name> # pick a branch and create a new worktree next to the repository
gz worktree add -a <name> # offer remote-tracking branches as well
gz worktree add -b <branch> <name> # create a new branch for it, picking its starting point
gz worktree remove # pick a worktree and remove it (with confirmation)
gz worktree remove --force # same, discarding modified and untracked files inside it (with a warning)
gz worktree prune # tidy up bookkeeping for worktrees whose directory is gone (with confirmation)
No arguments (list, then print the path)
- A candidate line is
<path> main|linked <branch|detached|bare>[ locked][ prunable]. - The preview shows the commit log of the highlighted worktree’s HEAD (bare worktrees and worktrees without a single commit get no preview).
- On confirmation only the path of the picked worktree goes to stdout; messages go to stderr.
Redirecting stdout to a file catches skim’s
drawing escapes in that file too —
gz worktree > out.txt and
gz log > log.txt behave the same. Pipes and
command substitution are fine, because the drawing goes to the
terminal, so cd "$(gz worktree)" works as expected.
gz worktree add <name>
| Argument | Description |
|---|---|
<NAME> | Name of the worktree to create (required positional argument). A name, not a path — separators are refused |
-a, --all | Include remote-tracking branches in the candidates, the same spelling as gz branch -a. Cannot be combined with -b |
-b <BRANCH> | Create a new branch with this name and put that in the worktree. No long spelling — git worktree add -b has none either |
- What you pick in the fuzzy finder is the branch to check out. Candidates are limited to branches not in use by another worktree (git cannot check out the same branch in two worktrees at once).
-
-aadds remote-tracking branches, exactly asgz branch -adoes. Pickingorigin/featurehands git the short name (feature) and git’s DWIM creates the local branch that tracks it. The “in use elsewhere” filter is applied to that short name, soorigin/featuredisappears from the list while a localfeatureis checked out in another worktree — picking it could only ever fail. A local branch and its remote counterpart are both listed, as ingz branch -a. -
The worktree is always created next to the repository root, whatever
directory you run the command from. Given a repository at
product/infrastructure/,gz worktree add samplecreatesproduct/sample/. A worktree holds the whole tree below.git, so placing it beside the repository reads more naturally than nesting it inside — and a worktree inside the repository shows up as an untracked embedded repository that you then have to gitignore. -
Because that is not where you ran the command, the resulting path is printed
to stderr once the worktree exists. (Not stdout:
git worktree addwritesHEAD is now at ...there itself, so stdout could never carry the path alone.) - The argument is a name. Anything containing a path separator (
../sample,a/b, an absolute path), as well as.and.., is refused with an explanation rather than being reinterpreted. - It runs
git worktree add -- <resolved path> <branch>. Names are never suggested automatically. - For a name starting with
-, writegz worktree add -- -dashy(that--is clap’s; fuzgit adds its own--when calling git).
git worktree add only writes out tracked files, so a
gitignored .claude/ would be missing in the new
worktree. fuzgit copies it over from the
worktree you ran the command in. Files that already exist on the
other side are left alone, symlinks are not
followed, and a failure is reported on stderr without failing the
command — the worktree itself was created. It is a copy,
not a link, so the two sides can diverge.
-b <branch> — when there is no branch left to pick
With one local branch (main) checked out by the main
worktree, the candidate list is empty and
gz worktree add is a dead end. -b is the
way out: it creates a new branch and puts that in the worktree.
Without -b you pick an existing local
branch. With it you pick the starting point
of the new branch — local branches, remote-tracking
branches and tags, exactly the candidates
gz branch create offers. The
finder header says which one you are looking at, because the rows
alone do not tell you.
-
The starting point is not fixed to HEAD. Cutting
a work branch from
mainis the common case, but the main worktree is often on something else — HEAD would give you the wrong parent.main/masterare sorted first, so Enter alone usually lands where you meant. -
A name already taken by a local branch stops the command
before the finder opens, and says that dropping
-bwould put that branch in the worktree instead. -
The upstream is left to git’s own default: it is set only
when the starting point is a remote-tracking branch, matching
what
gz branch createproduces. -
-band--no-installare independent. The dependency install and the.claude/copy run for-btoo.
Installing dependencies
After the worktree exists, fuzgit looks for lockfiles and installs
the dependencies. What it searches is the tracked files
— it asks git ls-files rather than walking the
filesystem, so node_modules/ and target/
are never in the way and there is no depth limit.
-
With more than one directory to install into, you pick
them. A line is
<path> <the commands that would run>, and the preview is the lockfile itself. Tab selects several; they run in order with[<n>/<total>]in front. - The directory you ran the command in starts selected, so pressing Enter installs exactly what it would have installed before this was a choice.
- With only one directory the finder does not open — a single-project repository behaves as it always did.
- Cargo and Go are not offered. Their dependencies live in a global cache and are fetched at build time, so a fresh worktree has nothing to install.
-
--no-installskips all of this, finder included.
gz worktree remove
- Candidates are linked worktrees only — the main worktree is not offered (git does not allow removing it).
- Locked worktrees, and worktrees with modified or untracked files when
--forceis not given, fail with git’s message as-is and a non-zero exit code. -f/--forcepasses--forcetogit worktree remove(once — a locked worktree is still refused), and the confirmation prompt then warns that modified and untracked files inside the worktree are discarded as well.
A confirmation prompt ([y/N]) comes first. Without
--force, a worktree holding modified or untracked
files is refused by git; with it, those files are discarded
along with the directory, so the prompt says so explicitly.
gz worktree prune
- It first runs
git worktree prune --dry-run --verboseand puts the worktrees that would be pruned, with the reason, into the confirmation prompt.git worktree pruneruns only if you approve. - With nothing to prune it reports so and exits with code 0.
gz worktree # 一覧から選んでパスを標準出力へ出す
cd "$(gz worktree)" # シェル連携(選んだ worktree へ移動する)
gz worktree add <name> # ブランチを選び、リポジトリの兄弟として worktree を作る
gz worktree add -a <name> # リモート追跡ブランチも候補に含める
gz worktree add -b <branch> <name> # 新しいブランチを作って入れる(作成元を選ぶ)
gz worktree remove # worktree を選んで削除する(確認あり)
gz worktree remove --force # 変更済み・未追跡のファイルごと削除する(警告つきの確認あり)
gz worktree prune # 実体を失った worktree の管理情報を整理する(確認あり)
引数なし(一覧 → パス出力)
- 候補行は
<パス> main|linked <ブランチ|detached|bare>[ locked][ prunable]です。 - プレビューには選択中 worktree の HEAD のコミットログを表示します(bare とコミットが 1 件も無い worktree はプレビューを出しません)。
- 決定すると選んだ worktree のパスだけを標準出力へ出します。メッセージ類は標準エラーです。
標準出力をファイルへリダイレクトすると、skim の描画エスケープも
そのファイルへ混ざります(gz worktree > out.txt /
gz log > log.txt のいずれも同じ)。パイプ・コマンド置換では
描画が端末側へ出るため、cd "$(gz worktree)" は期待どおり動作します。
gz worktree add <name>
| 引数 | 説明 |
|---|---|
<NAME> | 作成する worktree の名前(必須の位置引数)。パスではなく名前で、区切り文字は受け付けない |
-a, --all | リモート追跡ブランチも候補に含める(gz branch -a と同じ綴り)。-b とは併用できない |
-b <BRANCH> | この名前で新しいブランチを作り、それを worktree に入れる。長綴りは無い(git worktree add -b にも無いため) |
- fuzzy finder で選ぶのはチェックアウトするブランチです。候補は 他の worktree で使用中でないブランチに限ります (git は同じブランチを複数の worktree で同時にチェックアウトできないため)。
-
-aでリモート追跡ブランチも候補に含めます(gz branch -aとまったく同じ規則)。origin/featureを選ぶと git へは短縮名 (feature)を渡し、git の DWIM が追跡するローカルブランチを作ります。 「使用中」の判定はその短縮名に対して行うため、ローカルのfeatureが別の worktree でチェックアウト中ならorigin/featureも候補から消えます(選んでも必ず失敗するため)。 ローカルブランチとそのリモート側はgz branch -aと同じく両方並びます。 -
worktree は必ずリポジトリルートの兄弟に作成します。どのディレクトリで
コマンドを叩いても変わりません。リポジトリが
product/infrastructure/に あるとき、gz worktree add sampleはproduct/sample/を作ります。 worktree の中身は.gitのある階層まるごとなので、リポジトリと並べたほうが 素直に読めるためです(内側に作ると、本体からは未追跡の埋め込みリポジトリとして見え、.gitignoreの手当てが必要になります)。 -
叩いた場所とは違うところに作られるため、作成後にそのパスを標準エラーへ表示します。
(標準出力は使いません。
git worktree add自身がHEAD is now at ...をそちらへ書くため、パスだけを取り出せる状態には ならないからです。) - 引数は名前です。パス区切りを含むもの(
../sample/a/b/ 絶対パス)と./..は、読み替えずに理由を示して拒否します。 - 実行するのは
git worktree add -- <解決後のパス> <branch>です。名前の自動提案は行いません。 -
-で始まる名前を指定する場合はgz worktree add -- -dashyの ように書きます(clap 側の--であり、fuzgit は git へ渡す際にも別途--で保護します)。
git worktree add は追跡ファイルしか書き出さないため、gitignore された
.claude/ は新しい worktree に現れません。そこで、コマンドを実行した
worktree の .claude/ を複写します。複写先に既にある
ファイルは上書きせず残し、シンボリックリンクは辿りません。
失敗しても標準エラーへ知らせるだけでコマンドは失敗しません(worktree の作成自体は
成功しているため)。リンクではなく複写なので、両者は独立して変化します。
-b <branch> — 選べるブランチが無いとき
ローカルブランチが main 1 本で、それを本体が使用中——という
ごく普通の状態では候補がゼロになり、gz worktree add
はそこで行き止まりになります。-b はその抜け道で、新しいブランチを
作ってそれを worktree に入れます。
-b 無しで選ぶのは既存のローカルブランチ、
有りで選ぶのは新しいブランチの作成元です(ローカル・
リモート追跡ブランチ・タグ。gz branch create
とまったく同じ候補)。候補行だけでは区別が付かないため、どちらを見ているかは
finder のヘッダーが示します。
-
作成元は HEAD 固定ではありません。
mainから 作業ブランチを切るのが典型ですが、本体が別のブランチをチェックアウト中である ことは珍しくなく、HEAD 固定では望まない親から切ってしまいます。main/masterを先頭へ寄せているため、 多くの場合は Enter 1 回で意図した作成元になります。 -
既存のローカルブランチと同名の場合は、finder を開く前に停止します。
-bを外せばそのブランチを worktree に入れられることも案内します。 -
upstream は git の既定に委ねます。作成元がリモート追跡ブランチのときだけ
設定され、
gz branch createの結果と一致します。 -
-bと--no-installは独立です。 依存インストールと.claude/の複写は-bでも走ります。
依存インストール
worktree ができたあと、fuzgit は lockfile を探して依存をインストールします。
探すのは追跡ファイルです — ファイルシステムを走査せず
git ls-files に引かせるため、node_modules/ や
target/ を踏むことがなく、深さの制限もありません。
-
対象が複数あるときは選べます。候補行は
<パス> <実行されるコマンド>で、プレビューは lockfile そのものです。Tab で複数選択でき、[<n>/<全体>]を頭に付けて順に実行します。 - コマンドを叩いたディレクトリは選択済みで開くため、 そのまま Enter を押せば、選べるようになる前と同じものが入ります。
- 対象が 1 件のときは finder を開きません — 単一プロジェクトのリポジトリでは従来どおりの挙動です。
- Cargo と Go は候補になりません。依存がグローバルキャッシュに置かれ、 ビルド時に取得されるため、新しい worktree に入れるものがありません。
-
--no-installを付けると、finder を含めて一切行いません。
gz worktree remove
- 候補は linked worktree のみで、main worktree は候補に含めません(git が削除を許可しないため)。
- locked な worktree、および
--force無しでの変更済み・未追跡ファイルを含む worktree は、git のエラーをそのまま表示して非ゼロ終了します。 -f/--forceはgit worktree removeに--forceを(1 回だけ — locked な worktree は引き続き拒否されます)渡し、確認プロンプトに「worktree 内の変更済み・未追跡のファイルも破棄される」旨の警告を追記します。
実行前に確認プロンプト([y/N])を表示します。--force
無しでは変更済み・未追跡のファイルを抱えた worktree を git が拒否します。
付けた場合はそれらのファイルごとディレクトリが消えるため、プロンプトが
その旨を明示します。
gz worktree prune
-
先に
git worktree prune --dry-run --verboseを実行し、整理される worktree と 理由を確認プロンプトに提示します。承認された場合のみgit worktree pruneを 実行します。 - 対象が 1 件も無い場合は「整理する worktree はありません」と表示して終了コード 0 で終わります。
gz pr — picking a pull request to check out
gz pr — checkout する PR の選択
network通信
#
gz pr # pick an open pull request and check it out
gz pr --checks # also show the review decision and the CI status (slower)
gz pr --action # pick a pull request, then pick what to do with it
gz pr --worktree review-142 # check it out into a new worktree next to the repository
gz pr --worktree review-142 --no-install # …without installing dependencies
| Option | Description |
|---|---|
--checks | Also fetch the review decision and the CI status (noticeably slower) |
--action | After picking, show a menu of what to do (cannot be combined with --worktree) |
--worktree <NAME> | Check the pull request out into a new worktree with this name |
--no-install | Do not install dependencies after creating the worktree |
gz pr is the only command that needs
the GitHub CLI. Without it,
only this command stops, with a message pointing
at the install page; every other command keeps working. fuzgit
still assumes nothing but git.
-
Candidates are the open pull requests of the
current repository. A line is
#<number> <author> <title>, with a[draft]marker in its own column so the columns stay aligned whether or not a pull request is a draft. The head branch name is deliberately not on the line — it is often long enough to push the title off the screen, and the title is what you scan. It appears at the right edge of the preview’s summary instead. -
On confirmation it runs
gh pr checkout <number>. What you end up with is ordinary local git state — a branch, its tracking config, and a checkout. -
--actionopens a second menu: check the pull request out, show it (gh pr view), show the diff (gh pr diff), print the number, and print the URL. Only the last two write to stdout, so$(…)stays usable. -
Everything
ghprints comes straight fromgh. fuzgit never repeats it and never guesses at a cause.
Why the preview never waits
Every other fuzgit command builds its candidate list and previews
from local data only, because a preview is regenerated on
every cursor move and a network round trip there would
block the display (see Network operations).
gz pr is the single exception — and it breaks
the rule exactly once.
The candidate list is fetched with the pull request body riding along in the same call. By the time the finder opens, every preview is already in memory, so moving the cursor is a local string draw. Measured against a repository with 30 open pull requests, adding the body costs about 0.2 seconds.
reviewDecision and statusCheckRollup
are expensive on GitHub's side: the default fetch takes about
1.1 seconds where --checks takes
roughly three times that. They are opt-in for that reason, and
the wait is the same whether or not you end up picking anything.
--worktree <name> — reviewing without disturbing your tree
-
The argument is a name, not a path. The worktree
is created next to the repository root, exactly like
gz worktree add. Anything containing a path separator is refused. -
Afterwards fuzgit does what
gz worktree adddoes: copies your gitignored.claude/across (FR-33) and installs dependencies from the lockfile it finds.--no-installskips only the install; the.claude/copy still happens. - A name already taken by another worktree stops the command before the finder opens — you are never asked to pick and then told it will not work.
Run bare, gh pr checkout --worktree accepts a path
that already holds a worktree and simply checks out into it,
reporting success. That is why fuzgit refuses the name up front
rather than passing it through: “a new worktree was
created” and “an existing one was reused” look
the same otherwise.
fuzgit’s own messages switch with --lang, but
gh has no translations, so its lines stay English
even with ja. This is the same limitation as
git’s own output (see Language).
gz pr # open な PR を選んで checkout する
gz pr --checks # レビュー判定と CI の状況も表示する(遅くなる)
gz pr --action # PR を選んだあと、続けて行う操作も選ぶ
gz pr --worktree review-142 # リポジトリの隣に新しい worktree を作って checkout する
gz pr --worktree review-142 --no-install # …依存インストールは行わない
| オプション | 説明 |
|---|---|
--checks | レビュー判定と CI の状況も取得する(体感で遅くなる) |
--action | 選んだあと、続けて行う操作をメニューから選ぶ(--worktree とは併用不可) |
--worktree <NAME> | この名前の新しい worktree へ checkout する |
--no-install | worktree 作成後に依存インストールを行わない |
GitHub CLI を必要とするのは
gz pr だけです。無い場合はこのコマンドだけが停止し、
導入先を案内します。他のコマンドはそのまま動作します。fuzgit が前提とする
外部コマンドは引き続き git のみです。
-
候補は現在のリポジトリの open な PR です。候補行は
#<番号> <作者> <タイトル>で、[draft]の印は独立した列に置くため、draft の有無で桁がずれません。 head ブランチ名は意図的に載せていません — 長くなりがちでタイトルを画面外へ押し出してしまう一方、目で追うのは タイトルだからです。ブランチ名はプレビュー枠の右端に出ます。 -
決定すると
gh pr checkout <番号>を実行します。得られるのは ローカルの git 状態(ブランチ・追跡設定・チェックアウト)そのものです。 -
--actionを付けると 2 つ目のメニューが出ます — checkout する・詳細を表示する(gh pr view)・ 差分を表示する(gh pr diff)・番号を出力する・ URL を出力する。標準出力へ書くのは後ろの 2 つだけなので、$(…)はそのまま使えます。 -
ghの出力はそのまま流します。fuzgit は再掲もしませんし、 原因を推測することもしません。
プレビューが待たされない理由
fuzgit の他のコマンドは、候補一覧もプレビューもローカルの情報だけで作ります。
プレビューはカーソル移動のたびに作り直されるため、そこで
ネットワーク往復が起きると描画が止まるからです
(ネットワーク操作について参照)。
gz pr はその唯一の例外ですが、破るのは候補生成の 1 回だけです。
候補の取得では、PR の本文を同じ 1 回に相乗りさせています。 finder が開いた時点で全プレビューが手元にあるため、カーソル移動はローカルの 文字列描画で済みます。open な PR が 30 件のリポジトリでの実測で、本文の追加分は 約 0.2 秒です。
reviewDecision と statusCheckRollup は GitHub 側で
高くつきます。既定の取得が約 1.1 秒なのに対し、
--checks はおよそ 3 倍を要します。オプトインにしているのは
このためで、結局何も選ばなかった場合も同じだけ待つことになります。
--worktree <name> — 手元を汚さずにレビューする
-
引数はパスではなく名前です。作成先は
gz worktree addと同じくリポジトリルートの 兄弟に固定で、パス区切りを含むものは拒否します。 -
作成後は
gz worktree addと同じことをします — gitignore された.claude/を複写し(FR-33)、 見つけた lockfile から依存をインストールします。--no-installが 止めるのはインストールだけで、.claude/の複写は行われます。 - 他の worktree が既に使っている名前は、finder を開く前に停止します。 選ばせたあとで「使えません」と告げることはありません。
素の gh pr checkout --worktree は、既に worktree があるパスを
指定してもそこへチェックアウトして成功を報告します。fuzgit が名前を事前に
拒否するのはこのためです — そうしないと「新しく作られた」と
「既存のものが使われた」が見分けられません。
fuzgit 自身の文言は --lang で切り替わりますが、gh には
翻訳がないため、ja を選んでも gh の行は英語のままです。
git 本体の出力と同じ制約です(表示言語参照)。
Network operationsネットワーク操作について #
-
The only commands that use the network are
gz fetch,gz pullandgz pr. Every other command works purely from local repository data (pushing is left to plaingit push).gz pris also the only one that runs something other thangit— it needs theghCLI, which is not a required dependency. -
Previews never use the network, and candidate
generation does so in exactly one place. A preview is
regenerated every time the highlighted entry changes, so a
network round trip there (latency, timeouts, authentication
prompts) would block the display — that rule has no
exceptions. Candidate generation has one:
gz prlists pull requests from GitHub, and it fetches their bodies in the same call so its previews stay a local draw. Accordingly thegz fetchpreview is limited to local data (git remote get-url/git for-each-ref refs/remotes/<remote>) and never runsgit fetch --dry-runinside a preview; the list of updated refs is printed bygit fetchitself when it runs. Thegz pullpreview (commits not yet integrated) likewise comes from reading locally stored tracking refs and is therefore as of the last fetch. -
The only thing
gz pullsends over the network is thegit fetch <remote>per remote, run after the targets are fixed. Branches sharing an upstream remote are handled together, so there is one round trip per remote and never one per branch. Updating a branch that is not checked out (git fetch . <tracking ref>:refs/heads/<branch>) fetches from the repository itself and never goes out to the network. -
The ahead/behind in
gz statusand the right-hand side ofgz diff --upstreamboth come from reading local remote-tracking refs. Rungz fetchfirst if you want to compare against the latest state. -
Authentication is left to git.
git fetchruns with inherited stdio, so credential entry, credential helpers and progress output are all git’s own. fuzgit performs no timeouts, no retries and no direct socket handling whatsoever. -
gz fetch --siblingsruns its repositories in parallel;gz pullstays serial. The repositories are independent and the wait is network round trips, so they parallelise.gz pulldoes not: its per-remote fetch is effectively one call, and integrating branches writes to a single repository where the index and ref locks would collide. -
Without
--siblings, neighbouring repositories are not even offered as candidates. So that a mere change of directory cannot fire traffic at many repositories, the scan origin is always derived from the current repository and can never be given as a path. - Ctrl-C during a run is not handled specially: the SIGINT delivered to the foreground process group terminates fuzgit with it, and targets not yet started never run.
It captures each repository’s output so update tables
cannot interleave, and it forbids interaction
— GIT_TERMINAL_PROMPT=0,
GIT_ASKPASS="",
ssh -o BatchMode=yes -o ControlMaster=no — so
no prompt can appear with no way to tell which repository it came
from. Whatever fails there is run again, one at a time, with the
terminal attached.
-
ネットワークを使うのは
gz fetch・gz pull・gz prだけです。ほかのコマンドはすべてローカルのリポジトリ情報だけで 動作します(push は素のgit pushに委ねます)。gz prはgit以外の外部コマンドを起動する 唯一のコマンドでもあります —ghCLI を使いますが、 これは必須依存ではありません。 -
プレビューはネットワークを使いません。候補生成も 1 か所を除いて
使いません。プレビューは選択項目が変わるたびに生成されるため、
そこでネットワーク往復(遅延・タイムアウト・認証プロンプト)が発生すると描画が
ブロックされます — こちらに例外はありません。候補生成には 1 つだけ例外が
あり、
gz prは GitHub から PR を一覧します。 ただし本文を同じ 1 回で取り切るため、プレビューは ローカルの描画に閉じます。したがってgz fetchのプレビューは ローカル情報(git remote get-url/git for-each-ref refs/remotes/<remote>)に限定しており、git fetch --dry-runをプレビュー内で実行することはしません。 更新される参照の一覧はgit fetch自身が実行時に表示します。gz pullのプレビュー(未取り込みのコミット)も同様に、ローカルに 保存済みの追跡参照を読んだ結果であり、前回の fetch 時点の情報です。 -
gz pullが通信するのは、対象を確定したあとに実行する リモートごとのgit fetch <remote>だけです。 同じリモートを upstream に持つブランチをまとめて扱うため、通信は 1 リモートにつき 1 回で、ブランチごとには通信しません。チェックアウトしていないブランチの更新 (git fetch . <追跡参照>:refs/heads/<ブランチ>)は取得元が 自分自身のリポジトリであり、ネットワークへは出ません。 -
gz statusの ahead / behind とgz diff --upstreamの比較先は、いずれもローカルのリモート追跡参照を 読んだ結果です。最新の状態と比べたい場合は先にgz fetchを実行してください。 -
認証は git に委ねます。
git fetchは継承 stdio で 実行するため、認証情報の入力・credential helper・進捗表示はすべて git のものが そのまま動きます。fuzgit 側でのタイムアウト・リトライ・ ソケットの直接操作は一切行いません。 -
gz fetch --siblingsは並列、gz pullは直列 です。前者は対象が互いに独立した別リポジトリで、待ちの実体がネットワークの 往復であるため並列化できます。後者はリモートごとの fetch が実質 1 件であり、 ブランチの取り込みは同一リポジトリへの書き込みで index や参照の lock が 競合するため直列のままです。 -
--siblingsを指定しない限り、隣のリポジトリは候補にすら なりません。ディレクトリを移動しただけで多数のリポジトリへ通信が飛ぶことを 防ぐため、探索の起点は常に現在のリポジトリから導出し、パスでは指定できません。 - 実行中の Ctrl-C は独自に処理せず、前面プロセスグループへ届いた SIGINT で fuzgit ごと終了します(まだ着手していない対象は実行されません)。
リポジトリごとに出力をキャプチャして更新表が混ざらないようにし、さらに
対話を禁止します(GIT_TERMINAL_PROMPT=0・
GIT_ASKPASS=""・ssh -o BatchMode=yes -o ControlMaster=no)。
どのリポジトリのものか分からないプロンプトが出ないようにするためです。
そこで失敗した対象は、端末をつないだまま 1 件ずつ実行し直します。
Completion notifications完了通知 #
-
gz fetch --siblingsandgz pullcan post a desktop notification when they finish, which helps when you have stepped away from a long run. It is off unless you turn it on:git config --global fuzgit.notify true - Nothing is posted for runs shorter than ten seconds — below that you are still looking at the terminal. The threshold is fixed; there is no setting for it.
-
The body is the count only
(
3 succeeded / 1 failed). No repository, branch or path name is included: on macOS the text is handed toosascript, which interprets its argument as AppleScript, so user-derived strings are kept out of it by construction. -
Whether a banner actually appears depends on your environment.
macOS uses
osascriptand needs notifications allowed for your terminal application; Linux usesnotify-send, which may not be installed. fuzgit never treats that as a failure — the exit code is unchanged, and the reason is only written to the debug log (FUZGIT_DEBUG=1). - The tally is always written to stderr whether or not a notification appears, so the notification is a convenience and never the only way you learn the result.
-
gz fetch --siblingsとgz pullは、完了時に デスクトップ通知を出せます。長い実行の間に席を外しているときに役立ちます。 明示的に有効化しない限り出ません。git config --global fuzgit.notify true - 10 秒未満で終わった実行では通知しません。それより短ければ ユーザーはまだ端末を見ているためです。閾値は固定で、設定項目は設けていません。
-
本文は件数だけです(
成功 3 件 / 失敗 1 件)。 リポジトリ名・ブランチ名・パスは含めません。macOS では本文をosascriptへ渡しますが、これは引数を AppleScript として解釈するため、 ユーザー由来の文字列を構造的に混ぜないようにしています。 -
実際にバナーが表示されるかは環境によります。macOS は
osascriptを 使うため端末アプリへの通知許可が必要で、Linux はnotify-sendを 使うため未導入だと出ません。fuzgit はこれを失敗として扱いません。 終了コードは変わらず、理由はデバッグログ(FUZGIT_DEBUG=1)にだけ出ます。 - 通知が出るかどうかに関わらず集計は必ず標準エラーへ出します。 通知はあくまで補助であり、結果を知る唯一の経路にはなりません。
Key bindingsキー操作 #
The fuzzy finder uses skim’s default key bindings as they are.
| Key | Action |
|---|---|
| Typing | Filter incrementally |
| ↑ / ↓, Ctrl-p / Ctrl-n, Ctrl-k / Ctrl-j | Move between candidates |
| Tab / Shift-Tab | Toggle the selection of a candidate (multi-select mode only) |
| Enter | Confirm |
| Shift-↑ / Shift-↓ | Scroll the preview |
| Esc / Ctrl-C | Abort |
-
Multi-select is available in
cherry-pick/restore/add/stash push/commit/revert/status(file selection) /diff(file selection) /branch delete/branch cleanup/fetch --siblings/pull, and in the “inspect the conflicted files and mark them resolved” entry of the recovery menu. Pressing Enter without selecting anything with Tab targets the candidate under the cursor. -
Entries that start out selected:
gz commit(staged files),gz branch cleanup(every merged branch),gz fetch --siblings(the current repository) andgz pull(the current branch). All of them can be deselected with Tab. -
The selection is always reordered to follow the candidate list
before it is handed to git (the order skim returns is the order you
picked, which is not necessarily the list order). Commands where
the order matters each get their own direction:
gz cherry-pickoldest first,gz revertnewest first. - Aborting with Esc / Ctrl-C performs no git operation at all and exits with code 130.
fuzzy finder は skim の既定キーバインドをそのまま使います。
| キー | 動作 |
|---|---|
| 文字入力 | インクリメンタルに絞り込む |
| ↑ / ↓、Ctrl-p / Ctrl-n、Ctrl-k / Ctrl-j | 候補を移動する |
| Tab / Shift-Tab | 候補の選択を切り替える(複数選択モードのみ) |
| Enter | 決定する |
| Shift-↑ / Shift-↓ | プレビューをスクロールする |
| Esc / Ctrl-C | 中断する |
-
複数選択に対応するのは
cherry-pick/restore/add/stash push/commit/revert/status(ファイル選択)/diff(ファイル選択)/branch delete/branch cleanup/fetch --siblings/pull、および復帰メニューの 「コンフリクトファイルを確認して解決済みにする」です。Tab で 1 件も 選ばずに Enter を押した場合は、カーソル位置の候補が対象になります。 -
起動時から選択済みになるのは
gz commit(ステージ済みのファイル)、gz branch cleanup(merged なブランチ全件)、gz fetch --siblings(現在のリポジトリ)、gz pull(現在のブランチ)です。いずれも Tab で外せます。 -
選択結果は常に候補一覧を基準に並べ直してから git へ渡します
(skim が返す順序は選んだ順であり、候補の並び順とは限らないため)。
gz cherry-pickは古い順、gz revertは新しい順というように、 順序が意味を持つコマンドはそれぞれの向きへ揃えます。 - Esc / Ctrl-C で中断した場合、git 操作は一切実行せず 終了コード 130 で終了します。
Exit codes終了コード #
| Code | Meaning |
|---|---|
0 |
Success (including gz status with no changes, gz diff with no differences, gz pull --rebase with behind 0 and gz worktree prune with nothing to prune) |
1 |
Error (running outside a repository, zero candidates, a failing git command, and so on; the message goes to stderr).
gz fetch --siblings returns 1 if even one repository fails to fetch (the remaining repositories still run to the end and are then summarised).
gz pull likewise returns 1 if even one branch fails to integrate (the remaining branches still run to the end and are summarised; a failed branch is left in its pre-integration state).
|
2 |
Invalid command line (including bare gz and bare gz stash, where clap prints the help) |
130 |
The fuzzy finder was aborted (Esc / Ctrl-C), or a confirmation prompt was declined. No git operation is performed |
Run outside a git repository, fuzgit prints “Not a git repository. Run this command inside a git repository” and exits non-zero.
| コード | 意味 |
|---|---|
0 |
正常終了(gz status の変更ゼロ、gz diff の差分ゼロ、gz pull --rebase の behind ゼロ、gz worktree prune の対象ゼロを含む) |
1 |
エラー(リポジトリ外での実行、候補が 0 件、git コマンドの失敗など。メッセージは標準エラーへ)。
gz fetch --siblings は 1 件でも取得に失敗すると 1 になります
(残りのリポジトリは最後まで実行したうえで集計します)。
gz pull も 1 件でも取り込みに失敗すると 1 になります
(残りのブランチは最後まで実行したうえで集計します。失敗したブランチは取り込み前の状態のままです)
|
2 |
コマンドライン引数が不正(引数なしの gz / gz stash を含む。clap がヘルプを表示) |
130 |
fuzzy finder の中断(Esc / Ctrl-C)、または確認プロンプトでの否認。git 操作は実行されない |
git リポジトリ外で実行した場合は「git リポジトリではありません」と表示して非ゼロ終了します。
Out of scope / unsupportedスコープ外・非対応 #
Features deliberately left unimplemented. All of them can be done with plain git.
| Item | Reason |
|---|---|
Rebasing or merging a branch that is not checked out (gz pull in bulk) |
gz pull --rebase / --merge do exist, but only for the current branch. Doing it to a branch you have not checked out would mean temporarily switching the working tree or creating a temporary worktree — both of which put work in progress at risk. And if the k-th of N branches conflicted, truly returning to the pre-pull state would mean rolling back the k−1 that already succeeded, which needs something as dangerous as git reset --hard. Branches you did not check out therefore stay fast-forward only
|
--siblings / --prune / a positional branch name for gz pull |
--siblings would explode the number of selection combinations, and the “pick a branch per repository” model does not hold (pull is a write operation that advances local refs in somebody else’s repository, unlike gz fetch --siblings). --prune follows the policy that deleting tracking refs is stated explicitly via gz fetch --prune . A positional argument is not provided because if you can type the name, plain git already suffices (the existing rule of skipping the finder when there is a single candidate already gives a near-non-interactive experience)
|
Pushing (gz push) |
There is nothing worth picking. The branch is fixed to the current one, and a repository almost always has a single remote, so the finder would open with one candidate every time. Plain git push already does the job. Force push is out of scope on top of that: destroying remote history cannot be guaranteed safe by a confirmation prompt alone |
Reverting a merge commit (git revert -m) |
Picking the mainline requires understanding the history structure, and a fuzzy finder adds no value to that choice. When one is selected, fuzgit stops before running and points at plain git revert -m 1 <hash> |
Running --dry-run inside the gz fetch preview |
A preview runs anew for every highlighted entry, so a network round trip would block the display. Updated refs are printed by git fetch itself when it runs |
Recursive scanning, or a depth option (--depth etc.), for gz fetch --siblings |
One level below the parent directory already covers the use case; recursion would increase both the scan cost and the blast radius of network traffic. Repositories in deeper levels are not targeted |
An option to specify the scan origin of gz fetch --siblings as a path |
Accepting an arbitrary path would break the assumption shared by every command that the current repository is the origin, and would let traffic be aimed at unintended directories. The origin is fixed to the parent of the worktree root |
Per-repository remote selection in gz fetch --siblings |
It would mean repeating the finder once per repository, which breaks the operation model. Guessing a single remote implicitly is also avoided, in favour of the deterministic rule --all (every registered remote). Excluding a specific remote can be done on the git side with remote.<name>.skipFetchAll |
Fetching the branches of gz pull in parallel |
Its per-remote fetch is effectively a single call (one upstream remote in most repositories), and integrating branches writes to one repository, where the index, ref and packed-refs locks would collide. gz fetch --siblings is parallel, because the targets are separate repositories (see Network operations) |
Including bare repositories in the --siblings candidates |
There is no working tree for the fetched refs to land in. A bare repository such as foo.git falls outside the scan condition (the existence of <directory>/.git) and is never a candidate; a repository that has <directory>/.git but is configured bare is excluded and counted in the exclusion count shown in the header. This is a feature for the repositories you work in day to day |
| Following symlinked sibling directories | The scan range is limited to real entries directly under the parent directory, preventing the set of contacted hosts from expanding unexpectedly |
A [y/N] confirmation before gz fetch --siblings runs |
Making a multi-selection and pressing Enter is already an explicit decision, and a second confirmation is redundant. A fetch also does not damage local history (the scope of --prune is shown in the finder header) |
| Bulk operations other than fetch across sibling repositories (bulk status, bulk pull, etc.) | fetch is the one operation suited to bulk execution: read-direction, non-destructive and safe to re-run. Extending this to other operations would need its own requirements |
Custom signal handling during --siblings (e.g. Ctrl-C to skip the rest) |
With inherited stdio, SIGINT reaching the process group and terminating fuzgit with it is the expected behaviour. Custom control would be excessive |
| Automatic retry of failed repositories | The existing policy of adding no timeouts and no retries continues. The names of failed repositories appear in the summary line, so the user can decide about re-running |
tag vs tag in gz diff |
Rarely needed. Tags are still offered as the base of gz branch create, which is where they earn their place |
gz worktree move / lock / unlock / repair |
Rarely needed day to day, and each is a single plain git command |
gz worktree remove --force --force (forcing a locked worktree) |
A lock is an explicit “do not delete” mark. One --force (discarding modified and untracked files) is offered; nothing goes past the lock |
| A text input UI for branch names and worktree paths | skim has no text input UI. Names and paths are positional arguments (gz branch create <name> / gz worktree add <name>) and the fuzzy selection is limited to the starting point / the branch. gz worktree add also never suggests a directory name automatically |
| Hunk-level partial commit / stage | File-level selection covers the use case. Hunk selection does not fit skim’s candidate model (one line = one item) |
Running the autosquash rebase automatically after gz fixup |
History rewriting is never run automatically; the steps are printed to stderr and nothing more |
| A recovery menu for cherry-pick / revert / fetch | The recovery menu is limited to merge / rebase. Conflicts in cherry-pick / revert are left to git’s standard message and its --continue / --abort guidance |
| “Open the conflicted file in an editor” | That would launch $EDITOR directly without going through git, which needs a separate design decision to stay consistent with the no-shell policy |
意図的に実装していない機能です。いずれも素の git で実行できます。
| 項目 | 理由 |
|---|---|
チェックアウトしていないブランチの rebase / merge(gz pull の一括取り込み) |
gz pull --rebase / --merge は存在しますが、
対象は現在のブランチのみです。チェックアウトしていない
ブランチに対して行うには作業ツリーを一時的に切り替えるか一時 worktree を
作るしかなく、いずれも進行中の作業を危険に晒します。また N 本中 k 本目で
コンフリクトした場合、真に「pull 前」へ戻すには成功済みの k−1 本も
巻き戻す必要があり、git reset --hard 相当の危険な操作なしには
成立しません。そのため、チェックアウトしていないブランチは
fast-forward のみです
|
gz pull の --siblings / --prune / ブランチ名の位置引数 |
--siblings は選択の組み合わせが爆発し、リポジトリごとにブランチを選ぶ
操作モデルが成立しない(pull は他人のリポジトリのローカル参照を進める書き込み操作であり、
gz fetch --siblings と性質が異なる)。--prune は追跡参照の削除を
gz fetch --prune として明示指定する方針。
位置引数は、名前を打てるなら素の git で足りるため設けない(候補が 1 件なら finder を
省略する既存原則で非対話に近い使い勝手は確保される)
|
push(gz push) |
選ぶ価値のある軸が無い。対象ブランチは現在のブランチに固定され、リモートは 1 つだけのリポジトリがほとんどであるため、候補 1 件の finder が毎回開くだけになる。素の git push で足りる。加えて force push は、リモート履歴の破壊を確認プロンプトだけでは担保できないためスコープ外 |
マージコミットの revert(git revert -m) |
mainline の選択は履歴構造の理解を要し、fuzzy finder で「選ぶ」価値が乗らない。
選択された場合は実行前に停止し、素の git revert -m 1 <hash> を案内する
|
gz fetch のプレビューでの --dry-run 実行 |
プレビューは選択項目ごとに都度実行されるため、ネットワーク往復が描画をブロックする。更新された参照は git fetch 自身が実行時に表示する |
gz fetch --siblings の再帰探索・探索深度の指定(--depth 等) |
親ディレクトリ直下の 1 階層で用途を満たせており、再帰は走査コストとネットワークの影響範囲を同時に増やす。深い階層のリポジトリは対象にしない |
gz fetch --siblings の探索起点をパスで指定するオプション |
任意パスを受け取ると「現在のリポジトリを起点にする」という全コマンド共通の前提が崩れ、意図しないディレクトリへ通信を飛ばせてしまう。起点はワークツリー root の親に固定する |
gz fetch --siblings でのリポジトリごとのリモート選択 |
リポジトリ数だけ finder を繰り返すことになり操作モデルが成立しない。暗黙に 1 つのリモートを
推測するのも避け、--all(登録済みの全リモート)という決定的な規則を採る。
特定リモートの除外は git 側の remote.<name>.skipFetchAll で行える
|
gz pull のブランチ取り込みの並列化 |
リモートごとの fetch は対象数が実質 1 件(大半のリポジトリで upstream のリモートは 1 つ)であり、ブランチの取り込みは同一リポジトリへの書き込みで index・参照・packed-refs の lock が競合する。gz fetch --siblings は対象が別リポジトリであるため並列に実行する(ネットワーク操作について参照) |
bare リポジトリを --siblings の候補に含めること |
fetch した参照の反映先となる作業ツリーが無い。foo.git のような bare は
走査条件(<ディレクトリ>/.git の存在)から外れて候補にならず、
<ディレクトリ>/.git を持つが bare 設定のリポジトリは除外件数に数えて
ヘッダーへ示す。日常的に作業するリポジトリを対象とする機能である
|
| シンボリックリンクの兄弟ディレクトリを辿ること | 走査範囲を「親ディレクトリ直下の実体」に限定し、通信先が予期せず広がることを防ぐ |
gz fetch --siblings 実行前の [y/N] 確認プロンプト |
複数選択して Enter を押すこと自体が明示的な決定であり、二重確認は冗長。fetch はローカル履歴を壊さない操作でもある(--prune の適用範囲は finder のヘッダーで示す) |
| 兄弟リポジトリへの fetch 以外の一括操作(一括 status / 一括 pull 等) | fetch は「読み取り方向・非破壊・失敗しても再実行できる」唯一の一括実行に適した操作である。他の操作へ広げるのは別途要件から起こす |
--siblings 実行中の独自シグナルハンドリング(Ctrl-C で残りをスキップ等) |
継承 stdio のままプロセスグループへ SIGINT が届き fuzgit ごと終了するのが期待挙動。独自制御は過剰 |
| 失敗したリポジトリの自動リトライ | fuzgit 側でタイムアウト・リトライを行わない既存方針を継続する。失敗したリポジトリ名は集計行に出るため、再実行の判断はユーザーが行える |
gz diff の tag vs tag |
使用頻度が低い。タグは gz branch create のベース候補として引き続き選べる |
gz worktree の move / lock / unlock / repair |
日常頻度が低く、いずれも素の git で 1 コマンドで済む |
gz worktree remove --force --force(locked な worktree の強制削除) |
lock は「消すな」という明示の印。--force 1 回(変更済み・未追跡ファイルの破棄)までを提供し、それを越える手段は用意しない |
| ブランチ名・worktree パスのテキスト入力 UI |
skim にテキスト入力 UI は無い。名前・パスは位置引数
(gz branch create <name> / gz worktree add <name>)とし、
fuzzy 選択は作成元・ブランチに限定する。gz worktree add のディレクトリ名の
自動提案も行わない
|
| hunk 単位の部分 commit / stage | ファイル単位の選択で用途を満たす。hunk 選択は skim の候補モデル(行=項目)に乗らない |
gz fixup 後の autosquash rebase の自動実行 |
履歴改変の自動実行は行わない。手順を標準エラーへ表示するに留める |
| cherry-pick / revert / fetch の復帰メニュー | 復帰メニューは merge / rebase に限定する。cherry-pick / revert のコンフリクトは git の標準メッセージと --continue / --abort の案内に委ねる |
| コンフリクトファイルを「エディタで開く」 | git を介さず $EDITOR を直接起動する経路になり、シェル非経由方針との整合に別途設計判断が必要 |
Debuggingデバッグ #
$ FUZGIT_DEBUG=1 gz branch
[fuzgit] (B) git log --color=always --oneline --decorate -n 50 feature -- [LANGUAGE=en]
[fuzgit] (B) git switch feature [LANGUAGE=en]
$ FUZGIT_DEBUG=1 gz status
[fuzgit] (A) (cwd: .) git status --porcelain -z --untracked-files=all [LC_MESSAGES=C]
Setting the environment variable FUZGIT_DEBUG=1 prints
every git command fuzgit runs to stderr.
- It is enabled only when the value is exactly
1. Unset, empty,0,trueand anything else are all disabled. - The destination is always stderr (stdout is kept free for piping hashes, tag names and paths).
- The log lists the argument array as-is. Because it is printed on every preview generation, it can visibly mix with the drawing while the fuzzy finder is on screen.
- Commands that target another directory are printed as
[fuzgit] (A|B) (cwd: <directory>) git .... -
(A)marks a call whose output fuzgit parses: it always runs withLC_MESSAGES=Cso parsing cannot depend on the environment.(B)marks a call whose output you read (inherited stdio, previews, reports passed through): the resolved display language is propagated asLANGUAGE=<ja|en>. The variables that were set or removed are listed in brackets at the end of the line, so the log answers “which language did this git speak?” directly. See Language.
環境変数 FUZGIT_DEBUG=1 を指定すると、fuzgit が実行した git コマンドを
標準エラーへ出力します。
- 有効になるのは値が厳密に
1の場合だけです。未設定・空文字・0・trueなどはすべて無効です。 - 出力先は必ず標準エラーです(標準出力はハッシュ・タグ名・パスのパイプ用途のために空けてあります)。
- ログにはコマンドの引数配列がそのまま並びます。プレビュー生成のたびに出力されるため、fuzzy finder の表示中は画面の描画と混ざって見えることがあります。
- 別ディレクトリを対象に実行するコマンドは
[fuzgit] (A|B) (cwd: <ディレクトリ>) git ...の形式で出力します。 -
(A)はfuzgit が出力をパースする呼び出しで、実行環境に よってパースが壊れないよう常にLC_MESSAGES=Cで実行します。(B)はユーザーが出力を読む呼び出し(継承 stdio・プレビュー・ そのまま提示する報告)で、解決された表示言語をLANGUAGE=<ja|en>として伝播します。設定・削除した環境変数は 行末の角括弧に併記されるため、「この git は何語で話したのか」がログから直接 分かります。表示言語も参照してください。
Development開発 #
Quality gate品質ゲート
Confirm that all of these succeed, in this order, on every change.
以下の順にすべて成功することを、変更のたびに確認してください。
cargo build
cargo clippy --all-targets -- -D warnings
cargo fmt --check
cargo test
Testing policyテスト方針
- Interactive paths that take over the terminal (the TUI) are outside the scope of automated tests and are verified manually.
-
Automated tests cover pure logic (formatting candidates, assembling
git arguments, parsing
git status/git stash list/git worktree list) as unit tests, and non-interactive paths (--help, running outside a repository, zero candidates) as integration tests withassert_cmd. -
Paths involving the network (
gz fetch/gz pull) are not automated; only their non-interactive paths (no remotes, no upstream, zero candidates and similar errors) are verified. Real-world checks use a local bare repository as the remote and never connect to an external network.
- 端末(TUI)を占有する対話パスは自動テストの対象外とし、手動確認とします。
-
自動テストの対象は、候補の整形・git 引数の組み立て・
git status/git stash list/git worktree listのパースなどの純ロジック (単体テスト)と、--help・リポジトリ外実行・候補 0 件などの非対話パス (assert_cmdによる統合テスト)です。 -
ネットワークを伴う経路(
gz fetch/gz pull)は 自動テスト化せず、非対話パス(リモートゼロ・upstream 未設定・ 候補ゼロなどのエラー)のみを検証します。実機確認はローカルの bare リポジトリを remote に設定して行い、外部ネットワークへは接続しません。
Design principles設計方針
-
Read with gix, write by shelling out to
git. gix does not provide the write operations for switch / cherry-pick / restore / add / stash, so they are delegated to the system git in order to keep behavioural compatibility. The worktree listing is read withgit worktree list --porcelain -zrather than gix (gix cannot handle the main worktree or the checked-out branch). -
External commands always run as
Command::new("git").args([...]), i.e. with an argument array, never through a shell. Paths that come from the user are passed after--as the pathspec:(top,literal)<path>, removing any room for them to be interpreted as options or wildcards. - Previews do not hand skim a shell command string; git is executed from Rust and the result is displayed, which structurally prevents injection through candidate strings.
-
Positional arguments that cannot be protected with
--, such as branch names and commit hashes (switch/merge/rebase/fixup/revert/diff), are passed to git only after checking that the selection is present in the candidate list. The only values that get through originate from real refs enumerated by gix.gz pullverifies thatbranch.<name>.remoteis a registered remote name before runninggit fetch(the configuration can hold a URL directly, so without the check it could connect to something that was never enumerated). The refspecgz pulluses for branches that are not checked out carries no forcing+, so git rejects non-fast-forward updates and local commits cannot be lost. - No network access during candidate generation or previews.
-
The only command that touches anything outside the current
repository is
gz fetch --siblings. The scan origin is always derived from the current repository’s worktree root (no path argument is accepted) and is limited to one level under the parent directory. Sibling repositories are opened withgix::open, notgix::discover(discoverwalks upwards, so a directory without a.gitwould grab a repository above the scan range). The selection is checked for an exact match against the candidate list, using normalised absolute paths, before it becomes a target. -
Destructive operations (discarding changes with
restore,stash drop,branch delete/cleanup, history rewriting withrebase, the integration performed bypull --rebase/--merge,worktree remove/prune, and aborting a merge / rebase) are confirmed first.mergeis confirmed too, showing how many commits will come in and the conflict prediction. - History rewriting is never run automatically (
gz fixuponly prints the autosquash steps; it does not rebase). - Pushing is not provided at all, so neither is force push. Use plain
git push.
-
読み取りは gix、書き込みは
gitへのシェルアウト。 gix は switch / cherry-pick / restore / add / stash の書き込み操作を提供していないため、 挙動互換性を優先してシステムの git に委譲しています。worktree の一覧だけは gix ではなくgit worktree list --porcelain -zを読みます(gix は main worktree と チェックアウト中のブランチを扱えないため)。 -
外部コマンドは常に
Command::new("git").args([...])の引数配列渡しで 実行し、シェルを一切経由しません。ユーザー由来のパスは--の後ろに:(top,literal)<path>のパススペックとして渡し、オプションや ワイルドカードとして解釈される余地を排除しています。 - プレビューは skim にシェルコマンド文字列を渡す方式ではなく、Rust 側で git を実行した 結果を表示する方式を採り、候補文字列由来のインジェクションを構造的に防いでいます。
-
ブランチ名・コミットハッシュのように
--で保護できない位置引数 (switch/merge/rebase/fixup/revert/diff)は、 選択結果が候補一覧に含まれることを確かめてから git へ渡します。 渡る値は gix が列挙した実在の参照に由来するものだけです。gz pullはbranch.<name>.remoteが登録済みのリモート名であることを検証して からgit fetchします(設定には URL を直接書けるため、検証しないと 列挙していない対象へ接続することになります)。gz pullが チェックアウトしていないブランチを更新する refspec には、強制更新の+を 付けません(非 fast-forward の更新を git に拒否させ、ローカルのコミットを 失わせないためです)。 - 候補生成・プレビューでネットワークアクセスを行いません。
-
現在のリポジトリ以外に触れるのは
gz fetch --siblingsだけです。 走査の起点は常に現在のリポジトリのワークツリー root から導出し(パス引数を受け取りません)、 親ディレクトリ直下の 1 階層に限定します。兄弟のリポジトリを開くのはgix::openでありgix::discoverではありません (discoverは上位へ遡るため、.gitを持たないディレクトリから 走査範囲より上のリポジトリを掴んでしまいます)。選択結果は正規化済みの絶対パスで 候補一覧と完全一致することを確かめてから実行対象にします。 -
破壊的操作(
restoreによる変更破棄、stash drop、branch delete/cleanup、rebaseによる履歴改変、pull --rebase/--mergeの取り込み、worktree remove/prune、 merge / rebase のabort)は実行前に確認を挟みます。mergeにも 確認を設け、取り込まれるコミット数とコンフリクト予測を提示します。 - 履歴改変の自動実行は行いません(
gz fixupは autosquash の手順を表示するだけで rebase しません)。 - push 自体を提供しないため、force push も提供しません。素の
git pushを使ってください。
Module layoutモジュール構成
src/
├── main.rs # entry point (parse the CLI, dispatch, exit code)
├── lib.rs
├── cli.rs # command definitions via clap derive
├── error.rs # domain errors via thiserror
├── finder.rs # skim wrapper (candidates, preview, abort detection)
├── git/
│ ├── repo.rs # opening the repository with gix
│ ├── read.rs # reading candidate data via gix / git
│ ├── siblings.rs # scanning repositories under the parent directory (gz fetch --siblings only)
│ └── exec.rs # running git (run_git / capture_git) and the debug log
└── commands/ # the use case implementation of each subcommand
src/
├── main.rs # エントリポイント(CLI パース → dispatch → 終了コード)
├── lib.rs
├── cli.rs # clap derive によるコマンド定義
├── error.rs # thiserror によるドメインエラー
├── finder.rs # skim ラッパー(候補・プレビュー・中断判定)
├── git/
│ ├── repo.rs # gix によるリポジトリのオープン
│ ├── read.rs # gix / git による候補データの読み取り
│ ├── siblings.rs # 親ディレクトリ直下のリポジトリ探索(gz fetch --siblings 専用)
│ └── exec.rs # git の実行(run_git / capture_git)とデバッグログ
└── commands/ # 各サブコマンドのユースケース実装
Licenseライセンス #
MIT License. The full text is in LICENSE.
MIT License. 全文は LICENSE を参照してください。