mcpField
J
jj-workflow

jj-workflow

github.com/trevors開発93 回インストール
リポジトリ

jj-workflow について

jjを使う開発者向けに、変更の説明、ブランチ、リベース、競合処理、復旧の手順をまとめたガイドです。AI支援作業向けの非対話コマンド規則も示し、colocated利用ならチームにはGitとして見える運用を説明します。

主な機能

  1. 01非対話コマンドで変更を記述
  2. 02書き換え後も安定する変更IDの利用
  3. 03競合をコミット状態として管理
  4. 04並行する実験の作成と比較
  5. 05jj absorbによる修正の振り分け
  6. 06操作ログからの状態復旧

活用シーン

  1. 01浅い変更スタックの維持
  2. 02古い変更の修正と後続変更のリベース
  3. 03同じ基点から複数の実装を試行
  4. 04操作の取り消しやリポジトリ状態の復元

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trevors/dot-claude --skill jj-workflow

インストール後、Claude Code で/jj-workflowを入力して読み込まれたか確認します。

同梱ファイルREFERENCE.md

詳細

jj ワークフロー

基本方針

  1. コミットは簡単に作れますが、説明は必須です。 作業コピーは常にコミットです。「(no description set)」のままにしないでください。
  2. 自由に試してみましょう。oplog がセーフティネットになります。 すべての変更が記録されます。jj undo と jj op restore を使えば、どの操作も元に戻せます。
  3. コンフリクトは状態であり、緊急事態ではありません。 jj はコンフリクトを構造化データとしてコミットに保存します。コンフリクトがあってもリベースは成功します。準備ができたら解決してください。
  4. 変更 ID は作業を特定するためのものです。 書き換えるとコミットハッシュは変わりますが、変更 ID は変わりません。リベースやスカッシュをまたいで作業を参照するには、変更 ID を使ってください。
  5. ブックマークは GitHub 用であり、自分のためのものではありません。 匿名の変更で作業してください。プッシュが必要になったときだけブックマークを追加します。
  6. スタックは浅く保ちましょう。 早めにスカッシュしてください。整理せずに履歴を 10 コミット分も深くしないでください。
  7. 手動でスカッシュ先を指定するより absorb を使いましょう。 スタック全体にまたがって修正するときは、各ハンクの適切な配置先を jj に判断させてください。
  8. Colocated ならチームには見えません。 チームメイトには標準的な git として見えます。あなたが jj を使っていることはわかりません。

重要:AI 固有のルール

jj がエディターを開かないように、必ず -m フラグを使ってください。

# WRONG - opens editor, blocks AI
jj new
jj describe
jj commit
jj squash

# CORRECT - non-interactive
jj new -m "message"
jj describe -m "message"
jj commit -m "message"
jj squash -m "message"

次の対話型コマンドは使わないでください(非対話モードがありません)。

  • jj split / jj split -i
  • jj squash -i
  • jj diffedit

基本概念

作業コピー = コミット

ステージング領域はありません。ファイルを編集すると、すべて自動的に @(現在の変更)で追跡されます。git add は不要です。

  • @ = 現在の変更(作業コピーのコミット)
  • @- = 現在の変更の親
  • @-- = 祖父母
変更 ID とコミット ID

各変更には 2 つの識別子があります。

  • 変更 ID(例:kpqxywon)— 書き換え後も安定しています。作業を参照するにはこちらを使ってください。
  • コミット ID(例:a1b2c3d4)— 内容を書き換えると変わります。

スカッシュ、リベース、修正を行っても、変更 ID は変わりません。つまり、変更 ID を覚えておけば常にその変更を特定でき、git のコミットハッシュのように変わることはありません。

以前のバージョンにアクセスする(xyz/n 構文)

変更を書き換えるたびに、その変更が記録されます。<change-id>/n を使って以前のバージョンにアクセスできます。

  • xyz/0 — 最新(現在)のバージョン(xyz と同じ)
  • xyz/1 — 1 つ前のバージョン
  • xyz/2 — 2 つ前のバージョン

これは、変更を以前の状態に戻すときに便利です。

jj restore --from xyz/1 --to xyz    # Revert xyz to its previous contents
jj diff --from xyz/1 --to xyz      # See what changed between versions
コンフリクトは単なる状態です

リベースでコンフリクトが発生すると、jj はそのコンフリクトをコミットに記録して、処理を成功させます。「リベース進行中」のブロック状態も、--continue を実行する手順もありません。

  • コンフリクトのあるコミットの子孫は通常どおり作業できます
  • 都合のよいときにコンフリクトを解決できます。コミットをチェックアウトしてファイルを修正すれば完了です
  • jj log ではコンフリクトのあるコミットに印が付くため、見つけやすくなります

ワークフロー

スカッシュワークフロー(推奨)
jj describe -m "feat: what I'm building"   # State intent on current change
jj new -m "wip"                             # New empty change on top
# ... make changes ...
jj squash -m "feat: done"                   # Squash into parent
コミットワークフロー(よりシンプル)
# ... make changes ...
jj commit -m "feat: what I did"             # Describe + create new change in one step
# ... keep working ...

jj commit は jj describe -m "..." && jj new と同等です。

編集ワークフロー(スタック途中の修正)

古い変更を修正する必要がありますか?stash や rebase-i の手順は不要です。

jj edit <change-id>        # Switch working copy to that change
# ... make your fix ...
jj new -m "back to work"   # Return to tip (descendants auto-rebased)

編集した変更のすべての子孫は、自動的にリベースされます。

並行して試す
jj new main -m "approach A"           # Branch from main
jj new main -m "approach B"           # Another branch from main (not from A)
jj diff --from <A-id> --to <B-id>    # Compare approaches
jj edit <winner-id>                   # Continue with the winner
jj abandon <loser-id>                 # Discard the loser

Absorb:スマートなスカッシュ先の振り分け

変更のスタックがある状態で @ を修正すると、jj absorb は各ハンクを、その行が最後に変更された祖先へ自動的に振り分けます。

# You're at the top of a 3-commit stack, fixing bugs across all of them
jj absorb    # Each fix goes to the right commit automatically

スタック全体にまたがる修正には jj absorb を使ってください。変更の移動先が明確な場合は jj squash を使います。

ブックマークとプッシュ

ブックマークは jj における git ブランチに相当しますが、自動では進みません。明示的に移動する必要があります。

main へのプッシュ
jj bookmark set master -r @-        # Point bookmark at your commit (not empty @)
jj git push
フィーチャーブランチ
# Create and push
jj bookmark create feature-x -r @-
jj git push

# Update after more work
jj bookmark set feature-x -r @-
jj git push
PR のフィードバックへの対応
jj new feature-x- -m "address review feedback"
# ... make changes ...
jj squash -m "feat: updated per review"
jj bookmark set feature-x -r @-
jj git push

Revsets

Revset は、コミットを選択するための関数型言語です。@ と @- 以外にも、次の表現があります。

表現意味
@現在の作業コピー
@-親
@--祖父母
x+x の子
x::x のすべての子孫
::xx のすべての祖先
trunk()trunk/main コミット
bookmarks()ブックマークされたすべてのコミット
empty()空のコミット
divergent()分岐した変更
remote_tags()リモートタグ
diff_lines("text")差分が一致するコミット
description("text")説明で絞り込む
author("name")作成者で絞り込む

便利な例:

jj log -r 'trunk()..@'              # Everything between main and here
jj log -r '::@ & ~::trunk()'         # My branch only
jj log -r 'author("trevor")'         # My commits

リモートとの同期

jj git fetch                         # Pull from remote
jj rebase -d master@origin           # Rebase onto updated main

イミュータブルなコミットを一時的に無効化する

immutable_heads() で保護されたコミットを書き換える必要がある場合(例:リモートブックマークにスカッシュする場合):

# Disable protection (quote the key — parentheses are invalid TOML bare keys)
jj config set --repo 'revset-aliases."immutable_heads()"' 'none()'

# Do your rewrite
jj squash -m "updated message"

# ALWAYS restore protection immediately after
jj config set --repo 'revset-aliases."immutable_heads()"' 'builtin_immutable_heads() | remote_bookmarks()'

重要: immutable_heads() には括弧が含まれるため、NAME 引数では TOML キーをシェルクォートで囲む必要があります。内側を二重引用符にして、ドット区切りのキー全体を一重引用符で囲んでください:'revset-aliases."immutable_heads()"'。

重大:イミュータブル保護を無効化する前に、必ずユーザーに確認してください。 リモートブックマークを書き換えるには強制プッシュが必要で、共有履歴が書き換えられます。続行する前にユーザーに確認してください。イミュータブル性を黙って無効化してはいけません。

復旧

操作ログには、すべての変更が記録されます。完全に失われるものはありません。

jj op log                            # See all operations
jj undo                              # Undo last operation
jj op restore <id>                   # Jump to any past state
jj evolog                            # See how current change evolved
jj evolog -r <change-id>             # See how any change evolved

推奨設定

ユーザー設定は ~/.config/jj/config.toml にあります:

[remotes.origin]
auto-track-bookmarks = "*"

[revset-aliases]
# Prevent rewriting pushed commits
'immutable_heads()' = 'builtin_immutable_heads() | remote_bookmarks()'
# Shorthand for trunk
'trunk()' = 'master@origin'

中止する

rm -rf .jj    # Delete jj state, keep git unchanged

コメント