jujutsu について
jujutsu は、コーディングエージェント向けの Jujutsu(jj)バージョン管理ガイドです。可変コミット、自動リベース、Git 互換のワークフローに加え、非対話型環境でのコマンド実行と確認方法を説明します。
主な機能
- 01可変コミットと自動リベース
- 02revset によるコミット選択
- 03コミットの整理と変更の吸収
- 04ブックマークとワークスペースの管理
- 05Git リポジトリとの連携
- 06エージェント環境での操作指針
活用シーン
- 01jj リポジトリの履歴確認と編集
- 02作業をアトミックなコミットに整理
- 03複数ワークスペースでの並行作業
- 04Git の変更の取得とプッシュ
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ danverbraganza/ jujutsu-skill --skill jujutsuインストール後、Claude Code で/jujutsuを入力して読み込まれたか確認します。
詳細
Jujutsu (jj) バージョン管理システム
このスキルは、変更可能なコミットと自動リベースに対応した Git 互換の VCS、Jujutsu を使った作業に役立ちます。
jj v0.37.0 でテスト済み — 他のバージョンではコマンドが異なる場合があります。
重要:自動化/エージェント環境
エージェントとして実行する場合:
- コマンドがインタラクティブなページャー(
lessなど)を開いてエージェントが停止するのを防ぐため、必ず--no-pagerを使用してください。
# Always use --no-pager on commands that produce output
jj --no-pager log # NOT: jj log
jj --no-pager diff # NOT: jj diff
jj --no-pager show <id> # NOT: jj show <id>
- エディターのプロンプトに頼らず、メッセージをインラインで指定するために必ず
-mフラグを使用してください。
# Always use -m to avoid editor prompts
jj desc -m "message" # NOT: jj desc
jj squash -m "message" # NOT: jj squash (which opens editor)
エディターを使うコマンドは、非インタラクティブ環境では失敗します。
- 変更後(
squash、abandon、rebase、restore)、jj stで操作を確認し、成功したことを確かめてください。
基本概念
作業コピーはコミットです
jj では、作業ディレクトリは常にコミット(@ として参照)です。jj のコマンドを実行すると、変更は自動的にスナップショットされます。ステージングエリアはありません。
jj commit を実行する必要はありません。
コミットは変更可能です
重要:git とは異なり、jj のコミットは作成後も自由に変更できます。新しいコミットを作成せずに、説明の更新、変更のスカッシュ、リベース、吸収ができます。推奨される作業パターンについては、以下の「基本的なワークフロー」を参照してください。
Change ID と Commit ID
- Change ID:コミットが書き換えられても維持される安定した識別子(
tqpwlqmpなど)です。コミットを参照する際はこちらを優先してください。 - Commit ID:コミットの内容が変わると変更されるコンテンツハッシュ(
3ccf7581など)です。
Revset
jj は、コマンドでコミットを選択するために revset 言語を使用します。よく使う revset は次のとおりです。
@— 作業コピーのコミット@-— 作業コピーの親::@—@のすべての祖先@::—@のすべての子孫trunk()..@— trunk と@の間のコミット(自分のブランチ)bookmarks()— ブックマークが付いたすべてのコミット
revset は -r フラグとともに使用します:jj log -r 'trunk()..@'
基本的なワークフロー
作業の開始:まず説明を記述し、その後にコードを書く
コードを書く前に、必ずコミットメッセージを作成してください:
jj st で空のリビジョンであることを確認してください。そうでない場合は、次のように入力します。
jj new
# First, describe what you intend to do
jj desc -m "Add user authentication to login endpoint"
# Then make your changes - they automatically become part of this commit
# ... edit files ...
# Check status
jj st
アトミックコミットの作成
各コミットは、1 つの論理的な変更を表す必要があります。コミットメッセージには次の形式を使用してください。
Examples:
- "Add validation to user input forms"
- "Fix null pointer in payment processor"
- "Remove deprecated API endpoints"
- "Update dependencies to latest versions"
履歴の表示
# View recent commits
jj --no-pager log
# View with patches
jj --no-pager log -p
# View specific commit
jj --no-pager show <change-id>
# View diff of working copy (use --git for familiar +/- format)
jj --no-pager diff --git
重要:jj diff の出力形式:デフォルトの jj diff 出力では、左右に行番号が並ぶ形式(例:26 26:)が使用されます。git の +/- 接頭辞形式とは大きく異なります。これは正常で正しい出力であり、破損していたり、古い内容が表示されていたりするわけではありません。ただし、混乱を避けるため、標準的な +/- 行を使った統一 diff 形式にするには、必ず jj diff --git を使用してください。
コミット間の移動
# Create a new empty commit on top of current
jj new
# Create new commit with message
jj new -m "Commit message"
# Edit an existing commit (working copy becomes that commit)
jj edit <change-id>
# Edit the previous commit
jj prev -e
# Edit the next commit
jj next -e
コミットの調整
変更のスカッシュ
現在のコミットの変更を親コミットに移動します。
# Squash all changes into parent
jj squash
注:jj squash -i はインタラクティブ UI を開くため、エージェント環境では停止します。使用しないでください。
コミットの分割
警告:jj split はインタラクティブで、エージェント環境では停止します。コミットを分割するには、jj restore で変更を取り出してから、個別のコミットを手動で作成してください。
変更の吸収
変更された行を最後に編集したコミットに、変更を自動的に振り分けます。
# Absorb working copy changes into appropriate ancestor commits
jj absorb
コミットの破棄
コミットを完全に削除します(子孫はその親にリベースされます)。
jj abandon <change-id>
操作の取り消し
直前の jj 操作を元に戻します。
jj undo
これにより、リポジトリは直前のコマンドを実行する前の状態に戻ります。誤って abandon、squash、rebase した場合などに役立ちます。
コミットのリベース
コミットを別の親に移動します。
# Rebase current branch onto a destination
jj rebase -d <destination>
# Rebase a specific revision (without descendants) onto a destination
jj rebase -r <change-id> -d <destination>
# Rebase a revision and all its descendants
jj rebase -s <change-id> -d <destination>
# Rebase onto trunk (common: update your branch to latest main)
jj rebase -d main
ファイルの復元
特定のファイルの変更を破棄するか、別のリビジョンからファイルを復元します。
# Discard all uncommitted changes in working copy (restore from parent)
jj restore
# Discard changes to specific files
jj restore path/to/file.txt
# Restore files from a specific revision
jj restore --from <change-id> path/to/file.txt
ブックマーク(ブランチ)の操作
ブックマークは、jj における git のブランチに相当します。
# Create a bookmark at current commit
jj bookmark create my-feature -r@
# Move bookmark to a different commit
jj bookmark move my-feature --to <change-id>
# List bookmarks
jj --no-pager bookmark list
# Delete a bookmark
jj bookmark delete my-feature
ワークスペース
ワークスペースとは、作業コピーと、それに関連付けられたリポジトリのことです。1つのリポジトリに複数のワークスペースを持つことができ、それぞれが独自の作業ディレクトリと作業コピーのコミット(@)を持ちながら、同じコミット、操作、ブックマークを共有します。これは git worktree に相当する jj の機能です。
あるワークスペースで時間のかかるビルドやテストを実行しながら、別のワークスペースで編集する場合に便利です。ワークスペースは通常ほとんど必要にならない機能です。以下の基本事項を超える内容については、公式ドキュメントを参照してください。
よく使うコマンド
# Create a new workspace (defaults: name = basename of path, parent = current @'s parent)
jj workspace add ../my-tests
jj workspace add --name tests -r <change-id> ../my-tests # explicit name and base
# Inspect
jj --no-pager workspace list
jj workspace root [--name <ws>]
# Remove (does NOT delete files on disk — rm the directory separately)
jj workspace forget [<ws>]
# Rename current workspace
jj workspace rename <new-name>
jj log では、各ワークスペースの @ は <workspace-name>@ として表示されます。
主なセマンティクス
- デフォルトでは分離されています。
jj workspace addは、新しいワークスペースに新規の空のコミットを割り当てます。ワークスペースは最初から@を共有することはなく、ディスク上のファイルがワークスペース間でリアルタイムにミラーリングされることもありません。 - コマンドの境界で反映されます。 jj の各コマンドは、現在のワークスペースのファイルをスナップショットし、操作ログを読み取るため、他のワークスペースで作成されたコミットやブックマークを確認できます。ファイルシステムの変更を監視する機能はありません。
- 作業コピーが古くなった場合。 別のワークスペースによってこのワークスペースの
@が書き換えられた場合(例:jj squash、rebase、abandon)、jj workspace update-staleを実行するまで、jj はこのワークスペースでのコマンド実行を拒否します。コマンドが更新の途中で中断された場合も、同じ方法で復旧できます。 @の共有にはリスクがあります。jj edit <id>を使うと、警告なしに2つのワークスペースが同じ変更を指すことがあります。一方で変更を加えると、もう一方は古い状態になります。古い状態のワークスペースにスナップショットされていない編集があった場合、update-staleはそれを分岐したコミット(同じ変更 ID を持ち、jj logではxyz??と表示されます)として保持するため、解決が必要です。両方のワークスペースが読み取り専用でない限り、@の共有は避けてください。
エージェント向けガイダンス
jj workspace listには常に--no-pagerを指定してください。- 別のワークスペースですでに
@になっている変更をjj editしないでください。意図しない分岐の主な原因です。 jj workspace forget <name>も実行せずに、ワークスペースのディレクトリをrm -rfで削除しないでください。
Git 連携
既存の Git リポジトリを使用する
# Clone a git repository
jj git clone <url>
# Initialize jj in an existing git repo
jj git init --colocate
リモートの変更をフェッチする
# Fetch all branches from the default remote
jj git fetch
# Fetch from a specific remote
jj git fetch --remote <remote-name>
# Fetch specific branches
jj git fetch -b <branch-name>
フェッチ後、作業を更新されたトランクにリベースします:jj rebase -d main
jj と git を切り替える(コロケーションされたリポジトリのみ)
このセクションはコロケーションされたリポジトリ(.jj/ と .git/ の両方が存在するリポジトリ)にのみ適用されます。コロケーションされていないリポジトリでは、git コマンドを使わないでください。jj の状態が破損します。
コロケーションされたリポジトリでは、注意して jj と git の両方のコマンドを使用できます。
git モードに切り替える(例:マージのワークフローの場合):
# First, ensure your jj working copy is clean
jj st
# Then checkout a branch with git
git checkout <branch-name>
jj モードに戻す:
# Use jj edit to resume working with jj
jj edit <change-id>
重要な注意事項:
- jj の作業コピーが git の HEAD と異なる場合、git は未コミットの変更について警告することがあります。
- git に切り替える前に、jj で作業がコミット済みであることを必ず確認してください。
- git の操作後、jj は次のコマンド実行時に変更を検出して取り込みます。
変更をプッシュする
ユーザーから変更のプッシュを依頼された場合:
# Push a specific bookmark to the remote
jj git push -b <bookmark-name>
# Example: push the main bookmark
jj git push -b main
プッシュする前に、以下を確認してください:
- ブックマークが正しいコミットを指していること(ブックマークは git のブランチのように自動で進みません)
- コミットが整理され、アトミックであること
- ユーザーがプッシュを明示的に依頼していること
重要:git のブランチとは異なり、jj のブックマークは新しいコミットを作成しても自動で移動しません。プッシュする前に手動で更新する必要があります。
# Move an existing bookmark to the current commit
jj bookmark move my-feature --to @
# Then push it
jj git push -b my-feature
変更に対応するブックマークがない場合は、まず作成してください。
# Create a bookmark at the current commit
jj bookmark create my-feature
# Then push it
jj git push -b my-feature
競合の処理
jj では競合を含むコミットを作成でき、後から解決できます。
# View conflicts
jj st
エージェントによる競合解決:jj resolve(対話型)は使用しないでください。代わりに、競合マーカーを削除するよう競合ファイルを直接編集し、その後 jj st を実行して解決を確認してください。
コミット品質の維持
重要:コミットは変更可能なため、作業完了とする前に必ず調整してください。
- コミットを確認する:
jj --no-pager show @またはjj --no-pager diff --git - アトミックですか? 1つのコミットにつき、論理的な変更を1つにします
- メッセージは明確ですか? 句点を付けず、文頭を大文字にした命令形の動詞句を使います。例:「ログインエンドポイントを追加する」「決済処理のヌルポインターを修正する」「非推奨の API エンドポイントを削除する」
- 無関係な変更はありませんか?
jj restoreを使って変更を切り離し、別のコミットを作成します - 変更を別の場所に含めるべきですか?
jj squashまたはjj absorbを使います
クイックリファレンス
| 操作 | コマンド |
|---|---|
| コミットの説明を設定 | jj desc -m "message" |
| ステータスを表示 | jj st |
| ログを表示 | jj --no-pager log |
| 差分を表示 | jj --no-pager diff --git |
| 新しいコミット | jj new -m "message"(最初に jj st を実行します。@ が空の場合は省略します) |
| コミットを編集 | jj edit <id> |
| 親コミットにスカッシュ | jj squash |
| 自動振り分け | jj absorb |
| リベース | jj rebase -d <destination> |
| コミットを破棄 | jj abandon <id> |
| 直前の操作を元に戻す | jj undo |
| ファイルを復元 | jj restore [paths] |
| ブックマークを作成 | jj bookmark create <name> |
| リモートからフェッチ | jj git fetch |
| ブックマークをプッシュ | jj git push -b <name> |
| ワークスペースを追加 | jj workspace add <path> |
| ワークスペースを一覧表示 | jj --no-pager workspace list |
| ワークスペースを登録解除 | jj workspace forget [name] |
| 古くなった作業コピーを修正 | jj workspace update-stale |
ベストプラクティスのまとめ
- 最初に説明する:コーディングを始める前にコミットメッセージを設定します
- コミットごとに変更は1つ:コミットをアトミックにし、焦点を絞ります
- 変更 ID を使う:書き換え後も変わりません
- コミットを調整する:変更可能性を活用して、履歴をきれいに保ちます
- ワークフローを活用する:ステージングエリアもスタッシュもなく、コミットするだけです