Gitの複雑なコマンドに疲れた人への救世主。次世代VCS「jj(jujutsu)」が変える開発体験の未来(続き)

スポンサーリンク

《この記事の前半はnoteに投稿されています。是非ご覧ください。》

Gitの複雑なコマンドに疲れた人への救世主。次世代VCS「jj(jujutsu)」が変える開発体験の未来|アルクト
`git add`、`git commit`、`git stash`──。 毎日のように打ち込んでいるこれらのコマンドが、いつからか「思考の邪魔者」になっていると気づいたことはないでしょうか。 バージョン管理システム(VCS)は、本来ならコ...

スポンサーリンク

jjのアーキテクチャを深掘りする

Image_03

バックエンド設計とGit互換性

jjは設計の段階から、ユーザーインターフェース(UI)とデータの保存方法(バックエンド)を分離するアーキテクチャを採用しています。現在、実用的に使えるバックエンドはGitバックエンドのみですが、これは裏を返せば「jjで作成したコミットは普通のGitコミットに見える」ということを意味します。

GitHubへのプッシュも、チームメンバーのGitクライアントとの連携も、これまでどおり機能します。jjはあくまで「ローカルでのGit操作を改善するフロントエンド」として機能するため、既存のGitワークフローを壊すことなく導入できます。

(参照:jj公式GitHub)

コロケーションモード(--colocate)を使えば、.gitディレクトリをそのままにした状態でjjとGitを共存させることも可能です。つまり、VS Codeなど既存のGitツールを使いながら、コマンドラインではjjを使うという「いいとこ取り」の運用ができます。

Change IDとCommit IDの二重構造

Gitではコミットを識別するのはSHA-1/SHA-256のハッシュ値のみです。コミットを改変すると新しいハッシュが生成されるため、改変後のコミットを追跡するのが難しくなります。

jjはこれに対し、Change IDCommit IDという二種類の識別子を持ちます。Commit IDはGitのハッシュ同様に改変ごとに変わりますが、Change IDはコミットを改変しても変わりません。あるチェンジを修正すれば、jjは自動的にそのチェンジの子孫全てをリベースしてくれます。「どの変更を加工しているのか」が常に追跡可能な状態を保つことで、履歴の改変が大幅に安全かつ直感的になります。


革新的機能の詳解

Image_04

Working Copy Commits──「add」「commit」からの解放

この機能こそがjjのコアです。Gitのワークフローを振り返ると、変更→add→commitという3ステップが常に必要でした。jjではこれを1ステップに圧縮します。

# Gitの場合
git add src/feature.rs
git commit -m "Add new feature"

# jjの場合
# ファイルを保存するだけ──自動的にスナップショットが取られる
jj desc -m "Add new feature"  # コミットメッセージを後から(あるいは先に)書く

さらに注目すべきは、コミットメッセージを作業前に書けるという点です。jj new -m "Add new feature"でチェンジを作成してから実装を始めることができます。TDD(テスト駆動開発)のように、「何をするか」を先に宣言してから実装する習慣が、VCSレベルでサポートされるのです。

(参照:Steve KlabnikのJujutsuチュートリアル)

First-class Conflicts──コンフリクトを「エラー」から「データ」へ

Image_05

Gitではコンフリクトが発生した瞬間に作業が「凍結」されます。rebaseやmergeが中断状態になり、解消するまで他の作業ができません。

jjの設計はこれを根本から変えます。コンフリクトが発生しても、jjはオペレーションを成功させ、コンフリクトの情報をコミットの中に記録します。コミット自体がコンフリクト状態を持てるのです。

# jjでのリベース(コンフリクトがあっても成功する)
jj rebase -d main

# あとで確認・解消できる
jj status      # コンフリクトを含むファイルを確認
jj resolve     # マージツールで対話的に解消

この仕組みのもう一つの恩恵は、コンフリクトの伝播と自動解消です。ある中間コミットでコンフリクトを解消すると、その解消内容が自動的に子孫コミットにも伝播されます。Gitのgit rerere(再利用可能なコンフリクト解消記録)が自動的かつ確実に機能するイメージです。

(参照:jj公式ドキュメント──コンフリクト)

Revsets──強力なリビジョン選択言語

Image_06

jjのRevsets(リビジョンセット)は、コミットの集合を代数的に表現できる小さな関数型言語です。Mercurialの設計思想を受け継ぎ、jjの多くのコマンドで-rフラグとして利用できます。

# 基本的なRevsets
jj log -r @               # 現在のワーキングコピー
jj log -r @-              # 親コミット
jj log -r main..@         # mainからワーキングコピーまでの全コミット
jj log -r 'author("自分の名前")'  # 自分のコミットのみ
jj log -r 'description(substring:"fix")'  # コミットメッセージに"fix"を含むもの

# 複合的な指定
jj log -r '@ | ancestors(remote_bookmarks().., 2) | trunk()'

Revsets最大の魅力は、ログ表示のデフォルトをカスタマイズできる点です。スタックPR(複数PRを積み上げるワークフロー)を使うチームなら、「自分が関わるPRの範囲のみを表示する」アコーディオン型ビューを設定することも可能です。

(参照:Revsets理解ガイド)

Undo──すべての操作が取り消せる安心感

jjのオペレーションログ機能は、リポジトリに対する全ての操作を記録します。コミット、リベース、プッシュ、フェッチ──これら全てが履歴として残り、jj undoで直前の操作を取り消せます。

# 操作ログを確認
jj op log

# 直前の操作を取り消す
jj undo

# 特定の操作まで戻る
jj op restore <操作ID>

Gitではgit reflogを駆使しても難しかった「何かをやってしまった後の復元」が、jjでは極めてシンプルになります。この安心感は、特に大胆な履歴の改変を試みる際に大きな心理的安全性をもたらします。


Gitとjjのコマンドではなくワークフローごとの対比

以下の図でGitとjjの主要コマンドの対応関係を整理します。

Image_07

主要な操作を対比すると、jjの設計思想が明確に見えてきます。git add + git commitjj desc(メッセージを書く、実体はすでに自動記録済み)に集約され、git stashが不要となり、git checkout -bの代わりにjj newで簡潔に新しいチェンジを作れます。


Gitとjjのワークフロー──共存戦略の実際

jjを導入するにあたって最も重要な考え方は、「Gitを捨てない」という点です。ローカルでjjを使いながら、GitHubへはGit形式でpushするハイブリッドなワークフローが現実的かつ推奨される運用です。

コロケーションモードによる導入

既存のGitリポジトリへのjj導入は、以下のコマンド一つで完了します。

# 既存のGitリポジトリにjjを導入
cd your-existing-repo
jj git init --colocate

--colocateフラグにより、.gitディレクトリはそのまま保持されます。VS CodeのGit拡張機能など、既存のGitツールも引き続き利用できます。

典型的なjjワークフロー

# 新しい機能開発を始める
jj new -m "Add user authentication feature"
# ここからコードを書く──ファイルを保存するたびに自動スナップショット

# 作業途中で別件が入ったら
jj new -m "Fix urgent bug"
# 別件の実装──jjが自動的に現在の変更を記録

# 元の作業に戻る
jj edit <feature-change-id>

# GitHubへpushする
jj git push --bookmark feature/authentication

スタックPRのワークフロー

jjが特に輝くのはスタックPR(依存し合う複数のPRを積み上げるワークフロー)です。

# feature-1のチェンジを修正する(feature-2, feature-3が依存していても)
jj edit feature-1-change-id
# 修正を加える

# jjが自動的にfeature-2, feature-3をリベースしてくれる
jj log  # 全てのチェンジが更新済みであることを確認

Gitでは手動でのgit rebase --update-refsが必要だったこの操作が、jjでは自動化されます。

(参照:Jujutsu VCS パターンガイド)


jjの導入ステップ

インストール

jjはRust製のツールです。macOS、Linux、Windowsに対応しています。

# macOS(Homebrew)
brew install jj

# Linux/macOS(cargo経由)
cargo install --locked --bin jj jj-cli

# Windows(Winget)
winget install jj-vcs.jj

(参照:jj公式インストールガイド)

初期設定

# ユーザー情報の設定(--userはGitの--globalに相当)
jj config set --user user.name "Your Name"
jj config set --user user.email "your.email@example.com"

# 新しいリポジトリの作成
jj git init --colocate

# あるいはGitHubからクローン
jj git clone --colocate https://github.com/user/repo.git

シェル補完の設定

jjはシェル補完を標準でサポートしており、コマンド名だけでなくブックマーク名やリビジョンIDまで補完してくれます。

# bash
jj util completion bash >> ~/.bashrc

# zsh
jj util completion zsh >> ~/.zshrc

# fish
jj util completion fish >> ~/.config/fish/completions/jj.fish

2026年以降、VCSはどう進化していくのか

Image_08

jjはまだバージョン1.0に達しておらず(2025年12月時点でv0.24)、実験的なツールという位置づけです。しかし、Googleの内部でも使用されている実績と、活発なオープンソースコミュニティの存在が、このプロジェクトの本気度を示しています。

2024年9月にはGit Merge 2024での公式プレゼンテーション、VS Code拡張機能の整備、そしてTUIツール「lazyjj」の登場など、周辺エコシステムも急速に成熟しつつあります。

VCSの進化において、jjが提示した方向性は明確です。それは「ツールがエンジニアの思考を補助する」という方向性です。ステージングエリアの廃止、コンフリクトのデータ化、オペレーションログによる完全な可逆性──これらは全て「エンジニアが恐れずに実験できる環境」を作るための設計です。

Gitが「何でも可能だが何でも壊せる」ツールだとすれば、jjは「何でも可能で、何でも取り消せる」ツールを目指しています。

コードを書くことに集中したい──そのシンプルな願いに応えるツールとして、jjは2026年以降の開発体験を静かに、しかし確実に変えていくでしょう。


まとめ

jj(jujutsu)は、Gitの強力な資産を継承しながら、その使い勝手を根本から改善する次世代VCSです。主要な特徴を振り返ると以下のようになります。

Working Copy Commitsにより、git addgit commitの作法が不要となります。First-class Conflictsにより、コンフリクトはエラーではなくデータとして扱われ、作業を止める必要がありません。RevsetsによってGitのブランチよりも柔軟にコミットの集合を指定できます。jj undoによって、あらゆる操作が取り消し可能です。

Gitを完全に置き換える必要はなく、ローカルでjjを使いながらGitHubへはGit形式でpushするハイブリッドな運用が現実的です。まずbrew install jjでインストールし、jj git init --colocateで既存のプロジェクトに導入してみてください。「コードを書くことに集中できる」という感覚を、ぜひ体感してみてください。


参照

コメント

タイトルとURLをコピーしました