but について
GitButler CLI(`but`)を使うエージェント向けに、ワークスペースモードでの変更管理手順を示すスキルです。スタック型ブランチ、選択的なコミット、履歴編集と、他セッションの変更を保護するルールを扱います。
主な機能
- 01ワークスペースの同期と状態確認
- 02並列またはスタック型ブランチの作成
- 03選択したファイルやハンクのコミット
- 04コミット履歴の整理
- 05変更のプッシュとプルリクエスト作成
活用シーン
- 01GitButler ワークスペースでタスクを開始
- 02別々の変更を適切なブランチに割り当て
- 03指定したファイルやハンクをコミット
- 04プルリクエストのマージ後にワークスペースを同期
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ gaboe/ opencode-gitbutler --skill butインストール後、Claude Code で/butを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/cheatsheet.mdconcepts.mdexamples.mdreference.mdtutorial.md詳細
GitButler CLI スキル
ワークスペースモードで GitButler CLI(but コマンド)を使って作業するユーザーを支援します。
新しいセッションのワークフロー
コード変更を伴う新しいエージェントセッションでは、必ず次の手順に従ってください。
- まず同期する →
but pullを実行して最新の上流の変更を取得します(競合や古いベースを防ぎます) - 状態を確認する →
but statusを実行して既存のブランチと未ステージの変更を確認します - ブランチを決める →
- タスクに合致する既存のブランチがある場合 → 再利用します(すでに適用されています)
- 新しい作業の場合 →
but branch new <task-name>(例:feat/add-auth、fix/login-bug) - 未適用の作業を再開する場合 →
but apply <branch>
- 変更を加える → 必要に応じてファイルを編集します
- ステージしてコミットする →
but commit <branch> -m "message" --changes <id>,<id> - 調整する →
but absorbまたはbut squashを使って履歴を整理します - 準備ができたらプッシュする →
but push <branch> - PR を作成する →
but pr new <branch> -t(デフォルトのターゲットブランチを使用します)
ブランチの命名:慣例的なプレフィックスを使用します:feat/、fix/、chore/、refactor/
早めにコミットし、こまめにコミットしてください。 コミットの作成をためらわないでください。GitButler では履歴を簡単に編集できます。変更はいつでも既存のコミットに squash、reword、または absorb できます。大きな未コミットの変更より、小さくまとまったコミットのほうが適しています。
Write/Edit ツールの使用後
コミットの準備ができたら:
but status --jsonを実行して未コミットの変更を確認し、CLI ID を取得します- 該当するファイルを直接コミットします:
but commit <branch> -m "message" --changes <id>,<id>
コミット前に複数のファイルをまとめて編集できます。変更するたびにコミットする必要はありません。
重要な概念:ワークスペースモデル
GitButler ≠ 従来の Git
- 従来の Git:一度に扱うブランチは 1 つで、
git checkoutで切り替えます - GitButler:1 つのワークスペースで複数のスタックを同時に扱い、変更をスタックに割り当てます
つまり:
- ❌
git status、git commit、git checkoutは使わないでください - ✅
but status、but commit、butコマンドを使ってください - ✅ 読み取り専用の Git コマンドは使用できます(
git log、git diff)
厳守すべき安全ルール
- 自分が作成していない変更は絶対に破棄しないでください。
zz(未割り当て)には、他のセッション、エージェント、ユーザーの作業が含まれていることがよくあります。- 関係のない変更がある場合は、そのまま残し、破棄操作を行う前に確認してください。
- 作業の終了時に、自分の変更を
zzに残さないでください。- 編集後、
but status --jsonを実行し、ファイル ID またはハンク ID をbut stageまたはbut commit --changesで適切なブランチに移動してください。
- 編集後、
- コミット前にブランチの所有者を確認してください。
- 変更したファイルまたはハンクが意図したブランチ/タスクに属することを確認し、それらの ID のみをコミットしてください。
- セッションをまたいでブランチの所有権を尊重してください。
- 複数エージェントの環境では、他のエージェントセッションがブランチを所有している場合があります。このセッションで作成していないブランチのコミットメッセージ変更、名前変更、プッシュは絶対に行わないでください。
- 他のセッションのブランチを変更する必要がある場合は、まずユーザーに確認してください。
クイックスタート
インストール:
curl -sSL https://gitbutler.com/install.sh | sh
but setup # Initialize in your repo
but skill install --path <path> # Install/update skill (agents use --path with known location)
AI エージェント向けの注意:
- このスキルをプログラムでインストールまたは更新する場合は、必ず
--pathを使って正確なインストールディレクトリを指定してください。複数のインストール先がある場合、--detectフラグを使うとユーザーとの対話が必要になります。 - すべてのコマンドで
--jsonフラグを使用してください。これにより、構造化され、解析可能な出力を取得できます。これは特にbut status --jsonでワークスペースの状態を確実に解析するうえで重要です。
基本的なワークフロー:
but status --json # Always start here - shows workspace state (JSON for agents)
but branch new feature # Create new stack for work
# Make changes...
but commit <branch> -m "…" --changes <id>,<id> # Commit specific files by CLI ID
but push <branch> # Push to remote
基本コマンド
詳しいコマンド構文と利用可能なすべてのオプションについては、references/reference.mdを参照してください。 実践的な学習ガイドについては、references/tutorial.mdを参照してください。 1 ページで確認できるクイックリファレンスについては、references/cheatsheet.mdを参照してください。
AI エージェントへの重要事項: 構造化され、解析可能な出力を得るため、すべてのコマンドに--jsonフラグを追加してください。
状態の確認:
but status --json- 概要(まずここから始めてください。エージェントは必ず--jsonを使用してください)but status --json -f- ファイル一覧全体を含む概要(変更されたすべてのファイルを確認する必要がある場合に使用します)but show <id> --json- コミット/ブランチの詳細but diff <id>- 差分を表示
フラグの説明:
--json- 人が読みやすいテキストの代わりに、構造化された JSON を出力します(エージェントは必ず使用してください)-f- status の出力に詳細なファイル一覧を含めます(--jsonと併用できます:but status --json -f)
作業の整理:
but branch new <name>- 独立したブランチbut branch new <name> -a <anchor>- 積み重ねたブランチ(依存関係あり)but stage <file> <branch>- ファイルをブランチに事前割り当てします(任意。コミット前の整理用)
変更の作成:
but commit <branch> -m "msg" --changes <id>,<id>- 特定のファイルまたはハンクをコミットします(推奨)but commit <branch> -m "msg" -p <id>,<id>- 上記と同じですが、短いフラグを使用しますbut commit <branch> -m "msg"- コミットされていない変更をすべてブランチにコミットしますbut commit <branch> --only -m "msg"- 事前にステージされた変更のみをコミットします(--changesとは併用できません)but amend <file-id> <commit-id>- ファイルを特定のコミットに追加修正します(明示的に制御)but absorb <file-id>- ファイルを自動検出したコミットに吸収します(一致先を自動判定)but absorb <branch-id>- ブランチにステージされたすべての変更を吸収しますbut absorb- コミットされていない変更をすべて吸収します(注意して使用してください)
--changesに使用する ID の取得:
- ファイル ID:
but status --json- ファイル全体をコミットします - ハンク ID:
but diff --json- 個々のハンクをコミットします(1 つのファイルに複数の変更がある場合に、細かく制御できます)
履歴の編集:
but rub <source> <dest>- 汎用編集(ステージ/追加修正/スカッシュ/移動)but squash <commits>- コミットを統合しますbut reword <id>- コミットメッセージ/ブランチ名を変更します
リモート操作:
but pull- 上流の変更を取り込みますbut push [branch]- リモートにプッシュしますbut pr new <branch>- プッシュしてプルリクエストを作成します(自動的にプッシュされるため、事前のプッシュは不要です)but pr new <branch> -m "Title..."- PR メッセージをインラインで指定します(1 行目がタイトルで、残りが説明です)but pr new <branch> -F pr_message.txt- ファイルから PR メッセージを指定します(1 行目がタイトルで、残りが説明です)- スタックされたブランチでは、カスタムメッセージ(
-mまたは-F)は選択したブランチにのみ適用され、依存するブランチにはデフォルトが使用されます
重要な概念
ワークスペースモデル、依存関係の追跡、設計思想について詳しくは、references/concepts.mdを参照してください。
CLI ID: 各オブジェクトには短い ID が割り当てられます(例:コミットならc5、ブランチならbu)。これらを引数として使用してください。
並行ブランチとスタックブランチ:
- 並行:互いに依存しない作業
- スタック:ある機能が別の機能を基盤とする、依存関係のある作業
but rubプリミティブ: 組み合わせに応じて異なる処理を行う中核操作です。
- ファイル + ブランチ → ステージ
- ファイル + コミット → 追加修正
- コミット + コミット → スカッシュ
- コミット + ブランチ → 移動
ワークフローの例
詳しい手順や実際のシナリオについては、references/examples.mdを参照してください。
独立した作業の開始:
but status --json
but branch new api-endpoint
but branch new ui-update
# Make changes, then commit specific files to appropriate branches
but status --json # Get file CLI IDs
but commit api-endpoint -m "Add endpoint" --changes <api-file-id>
but commit ui-update -m "Update UI" --changes <ui-file-id>
特定のハンクのコミット(細かな制御):
but diff --json # See hunk IDs when a file has multiple changes
but commit <branch> -m "Fix first issue" --changes <hunk-id-1>
but commit <branch> -m "Fix second issue" --changes <hunk-id-2>
コミットの整理:
but absorb # Auto-amend changes
but status --json # Verify absorb result
but squash <branch> # Squash all commits in branch
競合の解決:
but resolve <commit> # Enter resolution mode
# Fix conflicts in editor
but resolve finish # Complete resolution
ワークスペースの管理:
but config target origin/test # Set default PR target (requires unapply all branches first)
but unapply <branch> # Remove branch from workspace (keeps commits)
but apply <branch> # Bring branch back into workspace
but teardown # Exit GitButler mode → normal git
but setup # Re-enter GitButler mode
but discard <ids> # Discard unstaged changes
マージ後の PR フロー
GitHub で PR がスカッシュマージされた後は、次の順序を必ず守ってください。
but unapply <merged-branch> # MUST do BEFORE pull - prevents orphan branch errors
but pull # Pull merged changes from remote
重要:マージされたブランチを適用解除する前に but pull を実行すると、GitButler で孤立ブランチの競合が発生します。必ず先に適用解除してください。
but unapply が失敗する場合(--delete-branch によるリモート削除後、ブランチがすでにワークスペースからなくなっている場合)、内部にゴーストスタックが残っているため、but pull も「resolution mismatch」エラーで失敗することがあります。この場合は GitButler のデスクトップアプリで対処できます。ユーザーに GUI から but pull を実行するよう伝えてください。別の方法として、but teardown → but setup → but config target origin/<branch> を実行してリセットできます。
but teardown → but setup の後:ターゲット設定がリセットされます。もう一度 but config target origin/<branch> を実行してください。
--no-hooks を安全に使う
変更とは無関係の既存エラーが原因で pre-commit フックが失敗する場合は、--no-hooks を使用してください。ただし、これを使うとフォーマッターもスキップされます。
bun run format # Format FIRST
but commit <branch> -m "msg" --changes <ids> --no-hooks # Then commit without hooks
別の方法として、通常どおりコミットし、フォーマッターによる修正を吸収できます。
but commit <branch> -m "msg" --changes <ids> # Commit (hooks may fix formatting)
but absorb # Absorb any auto-formatted changes
既知の問題と回避策
| 問題 | 発生すること | 回避策 |
|---|---|---|
but resolve でターゲット設定が失われる | resolve モードに入った後、but config target が「未設定」に戻ります | but resolve finish の後に、もう一度 but config target origin/<branch> を実行します。finish が失敗した場合は、git checkout gitbutler/workspace → but teardown → but setup の順に実行します |
but absorb のハンクロック | 別のブランチにある別のコミットによってハンクがロックされていると、Absorb が誤ったコミットにハンクを割り当てます | absorb の代わりに but amend <file> <commit> を使うと、明示的に制御できます |
but pr new に --base フラグがない | 常にデフォルトのターゲットに対して PR を作成します | 先にターゲットを設定します:but config target origin/<branch> |
but config target の変更に unapply が必要 | ブランチが適用されている状態では、ターゲットを変更できません | すべてのブランチに but unapply を実行 → ターゲットを変更 → but apply を実行します |
but config forge auth が対話型 | 非対話型のエージェントモードでは実行できません | ユーザーがターミナルで実行し、GitHub で組織へのアクセスを許可する必要があります |
but commit の pre-commit フックが失敗する | 変更とは関係のない既存のエラーが原因でフックが失敗します | エラーが変更に起因しない場合は but commit --no-hooks を実行します。--no-hooks はフォーマッターをスキップするため、必ず最初に bun run format を実行してください |
but branch delete で最後のセグメントを削除できない | 削除すると匿名セグメントが残る場合は、削除できません | delete の代わりに but unapply を使用します |
but stage のプレフィックス一致 | ブランチ名は省略できます | but stage <id> ch は chore/gitbutler-setup に対して機能します |
but discard のハンク範囲エラー | ファイル単位の変更を破棄すると、ハンク範囲エラーが発生することがあります | ファイル単位で破棄する場合は、but discard の代わりに git checkout -- <file> を使用します |
but teardown + but setup でターゲットがリセットされる | teardown/setup のサイクル後に、ターゲット設定が失われます | setup の後に、もう一度 but config target origin/<branch> を実行します |
Lefthook の pre-commit.old が蓄積する | Lefthook が pre-commit.old のバックアップを作成し、次回のインストール時に競合します | package.json の prepare スクリプトに rm -f .git/hooks/pre-commit.old を追加します |
unapply の前に but pull を実行する | マージ済みブランチを適用したまま pull すると、孤立エラーが発生します | but pull の前に、必ず but unapply <merged-branch> を実行します |
リモートブランチ削除後の but unapply | リモートでブランチが削除されていると(マージ時の --delete-branch など)、but unapply は「branch not found」で失敗し、その後の but pull は「resolution mismatch」で失敗します | GitButler デスクトップアプリを使って pull するか、but teardown → but setup → but config target origin/<branch> の順に実行します |
分割ハンクのファイルが zz に残る | ファイルのハンクが別々のブランチ上のコミットにロックされています。GitButler は stack_id=None を設定し、プラグインはロック参照によってファイルを「処理済み」とみなします | 各ハンクを手動でコミットします。but diff --json でハンク ID を取得し、各 ID に対して but commit <branch> -m "msg" --changes <hunk-id> を実行します |
| プラグインの自動クリーンアップで空のブランチが残る | ge-branch-* のクリーンアップは約 12% の確率で失敗し、ユーザーが名前を付けた空のブランチは自動クリーンアップされません | /b-branch-gc コマンドを実行するか、but unapply <branch-id> を手動で実行します |
| 通知がエージェントに届かない | 観測されたセッションでは、プラグインの通知配信率は約 55% です(キュー登録 259 件に対して配信 142 件) | but status --json で必ず状態を確認し、<system-reminder> 通知だけに頼らないでください |
| ワークスペースの投影の不一致 | but status ではブランチ/スタックが表示されるものの、but unapply <branch> または GUI の stack_details ではスタックがワークスペース内に見つからないと表示される | これは GitButler のメタデータ破損として扱い、Git の履歴の問題とは考えないでください。その場での変更を停止し、サポート用にログ、プロジェクト、コミットグラフを保存してから、but teardown → .git/gitbutler をバックアップ → but setup の順に実行してください。問題が続く場合は、新しいクローン/ワークツリーを使用してください。 |
resolve/rebase の繰り返し後に多数の (no changes) コミットができる | スタックに、upstream とパッチが同等の合成コミットや、再適用された重複コミットが蓄積される | その場で解決を繰り返さないでください。参照を固定し、git cherry -v でパッチが同等のコミットを特定してから、壊れた履歴を維持するのではなく、論理的なベースからクリーンなブランチを再構築してください。 |
| あるスタックを適用すると別のスタックが自動的に適用解除される | GitButler が、要求されたスタックを適用するために別のスタックを適用解除する必要があったと表示する | スタックの内容または祖先が重複しています。現在アクティブな競合スタックを先に適用解除するか、意図したスタックの境界を再構築し、同時に適用される論理チェーンを 1 つだけにしてください。 |
投影エラーにより but push がブロックされる | ワークスペース/スタックのメタデータは壊れているものの、Git の生の参照は正常である | リモートの祖先関係を修復することが目的の場合は、生の Git を使ってブランチ参照を確認し、最後の手段として git push --force-with-lease を使用してください。その後、gitbutler/workspace に戻り、but setup でメタデータを再初期化してください。 |
zz でファイルがスタックした場合の診断
ファイルが zz(未割り当て)でスタックし、自動的に復旧しない場合:
-
原因を特定します:
but status --json -f # Look for files in zz with [LOCKED] markers but diff --json # Get hunk-level IDs and see lock targets -
ハンクが異なるブランチにロックされている場合(ハンク分割のシナリオ):
- 各ハンクは、ロックされているブランチに個別にコミットする必要があります
- 各ハンクに対して
but commit <branch> -m "msg" --changes <hunk-id>を実行します - または
but rub <hunk-id> <commit-id>で、ロックされているコミットに修正を加えます
-
ファイルにロックがないのに、まだ
zzにある場合:- プラグインの
after-editがエラーを出さずに失敗した可能性があります。手動でステージしてください but stage <file-id> <branch>を実行するか、--changesを指定してコミットします
- プラグインの
-
but cursor stopの後に多数のファイルがスタックした場合:- 各ファイルに対して
but rub <file-id> <branch-id>を実行し、強制的に割り当てます - これは最も信頼性の高い復旧方法です
- 各ファイルに対して
重要なポイント: 自動復旧では、複数ブランチにロックされたファイルは修復できません。zz に [LOCKED] が表示されている場合は、手動での対応が必要です。
壊れたスタックの外科的修復
通常の but resolve ではすぐに収束させられないほどスタックが損傷している場合(たとえば:
- 競合したコミットが何度も再び現れる、
git cherry -vにパッチが同等の重複が多数表示される、- GitButler で
(no changes)と表示されたコミットが多数ある、 - または 1 つのコミットに
.auto-resolution/**など明らかに不要なスナップショットデータが含まれている、
壊れた履歴を維持しようとせず、外科的修復を行ってください。
外科的修復が適切な場合
- 生の Git グラフは理解できるものの、GitButler のメタデータ/履歴の再生状況は理解できない場合。
- 現在のブランチ履歴に作業内容が明確に反映されていなくても、意図した論理的な作業レイヤーをはっきり特定できる場合。
- 混在したコミットに、実際の機能ファイルと、明らかに誤って含まれた不要なデータが混在している場合。
外科的な修復ワークフロー
-
まず、すべてを凍結します
- 現在壊れているブランチのバックアップ用参照を作成します。
- ワークスペースの未コミット変更やフックの更新によるノイズをスタッシュします。
-
クリーンな論理上のベースを見つけます
git cherry -v <base> <branch>を使って、パッチが同一の重複コミットと、実際に固有のコミットを切り分けます。git log --reverse <base>..<branch>を使って、ブランチのコミット階層を順番に確認します。
-
壊れたブランチの履歴ではなく、クリーンなベースから再構築します
- 意図したベースからスクラッチブランチを作成します。
- クリーンなコミットだけをチェリーピックします。
- コミットが汚染されている場合(たとえば
.auto-resolution/**を追加している場合)は、そのコミットまたは既存ブランチの先端から、意図したパスだけをファイル単位でチェックアウトして、新しいクリーンなコミットを作成します。
-
再構築した各階層を個別に検証します
git diff --name-only <base>..<layer>で、階層間のファイル差分を比較します。- 参照を置き換える前に、再構築したスタックに対してプロジェクトの検証(
bun run check、ビルド/テスト/アナライザーなど)を実行します。
-
クリーンなスタックが実証されてから参照を置き換えます
- 実際のブランチ参照を、再構築したスクラッチ参照に移動します。
- 祖先関係とチェックを確認してから、
--force-with-leaseを使って強制プッシュします。
実際には、なぜこれが速いのか
外科的な修復は、競合の解決を繰り返すより大がかりに思えます。しかし、スタックが重複した再適用/(no changes)/メタデータ破損の状態に入った場合は、履歴上のすべての記録を維持するより、論理上の差分を再構築するほうが通常は速く、安全です。
重要な安全ルール
- 自分が作成していない変更を、絶対に破棄しないでください。
zzに割り当てられていない変更は、他のエージェント、セッション、またはユーザーのものかもしれません。認識できない変更に対してbut discardまたはgit checkout --を実行する前に、必ずユーザーに確認してください。GitButler ワークスペースでは複数の担当者が並行して作業するため、「古い」または「すでにマージ済み」の変更を破棄してよいと決めつけるのは破壊的です。 - 自分の変更は、すぐに必ずブランチに割り当ててください。 編集内容を
zz(未割り当て)に残さないでください。ファイルを編集した後、but stage <file-id> <branch>で作業ブランチにステージするか、--changesを使って直接コミットします。
ガイドライン
- まず
but status --jsonを実行して、現在の状態を把握します(エージェントは必ず--jsonを使ってください)。 - 独立した作業テーマごとに新しいスタックを作成します。
- 特定のファイルを直接コミットするには
--changesを使います。先にステージする必要はありません。 - 早めに、こまめにコミットします。完璧になるまで待たないでください。従来の Git と異なり、GitButler では
absorb、squash、rewordを使って履歴を簡単に編集できます。大きな未コミット変更をため込むより、後で調整できる小さなアトミックコミットを作成するほうが適切です。 - エージェントとして実行する場合は、すべてのコマンドで
--jsonフラグを使ってください。これにより、人間向けのテキストではなく、構造化された解析可能な出力が得られます。 - 判断に迷う場合は、
--dry-runフラグ(push、absorb)を使います。 but pullを頻繁に実行してください。セッション開始時、ブランチ作成前、プッシュ前に実行します。ワークスペースが古いと、マージ競合が発生します。- このスキルを更新する際は、プロンプトが表示されないよう
but skill install --path <known-path>を使います。 - 作業を終える前に、ロックされた
zzファイルがないか確認してください。but status --json -fを実行し、[LOCKED]マーカーが付いたzz内のファイルを探します。これらは自動では復元されません。--changes <hunk-id>を使って、各ハンクを正しいブランチに手動でコミットする必要があります。詳細は references/concepts.md — Hunk Locking を参照してください。 - 通知だけを信用しないでください。プラグインの通知配信率は約55%です。ブランチの割り当てやコミット状態について決めつける前に、必ず
but status --jsonでワークスペースの状態を確認してください。
プラグインの自動動作(バックグラウンドで行われる処理)
GitButler プラグインはいくつかの処理を自動的に実行します。これらを自分で行う必要はありません。ただし、重複作業や予期しない状態変更による混乱を避けるため、これらの処理が行われることを把握しておいてください。
| 動作 | トリガー | 内容 |
|---|---|---|
| ファイルの自動割り当て | ファイルを編集するたび | ファイルを所有するブランチを特定し、but cursor after-edit または but rub を実行して割り当てます |
| 自動コミット | セッションがアイドル状態になったとき(エージェントが編集を停止したとき) | but cursor stop を実行し、コミットされていない変更をすべて、それぞれ割り当てられたブランチにコミットします |
| LLM によるコミットメッセージの書き換え | 自動コミットの後 | 実際の差分に基づいて、Claude Haiku を使用し、一般的なコミットメッセージを書き換えます |
| ブランチ名の変更 | 自動コミットの後 | ge-branch-* ブランチの名前を、ユーザーのプロンプトに基づいたわかりやすい名前に変更します |
| 空のブランチのクリーンアップ | 自動コミットの後 | コミット数が 0 の ge-branch-* ブランチを削除します(成功率は約 88%) |
| セッションタイトルの同期 | 自動コミットの後 | ブランチ名をもとにセッションタイトルを更新します |
| コンテキストの注入 | エージェントのメッセージごとに送信前 | ワークスペースの通知(ブランチの作成、コミットなど)を含む <system-reminder> を注入します |
これが意味すること
ge-branch-*ブランチの名前を手動で変更しないでください — プラグインがアイドル状態になった後に変更します- 自動生成されたコミットメッセージを書き換えないでください — プラグインが LLM を使って書き換えます
- 予期しないコミットが見つかった場合 — アイドルイベント中にプラグインが自動コミットしたか確認してください
- 通知の到達率は約 55% です — 注入された通知がすべて届くわけではありません。通知に頼らず、
but status --jsonで常に状態を確認してください - 空のブランチのクリーンアップは失敗することがあります — 古い
ge-branch-*ブランチが残っている場合は、/b-branch-gcを実行してください