はじめに
Jujutsu(コマンド名 jj)はバージョン管理システムです。一番古いタグが2022年3月のv0.3.0なので、バージョン管理システムの世界ではかなりの新顔ということになりますね。このJujutsuが最近のお気に入りなので推させてくれ! というのが本記事になります。
Jujutsuの主な特長は以下の通りです。
- Gitとの互換性
- シンプルで合理的なユーザーインターフェース
- 明快で強力なブランチ操作、特に衝突解決
目指しているのはGit互換というよりはマルチバックエンドらしいのですが、Gitがデファクト化しているこのご時世なのでGitバックエンドが特に成熟しているみたいな状況のようです。SimpleBackendというのもありますが概念実証レベルで実用には適さず、またGoogle社内には独自バージョン管理システムに対応したバックエンドがあるようですが、まあそのへんは中の人じゃないのでよくわかりません... ともあれ、これによりJujutsuはGitとデータ / プロトコル互換のバージョン管理システムとして使用できます。
ユーザーインターフェースについてはわかりやすく、間違えにくく、万が一間違えても簡単にやり直せることに注力して設計されているように感じます。実はユーザーに発想の転換を促すようなところがあり、最初のうちは戸惑うこともあるかもしれません。しかし、それによりメンタルモデルがシンプルで合理的なものになっていることをすぐに実感できると思います。このあたりについては後ほど詳しく解説します。
リベースやスカッシュなどのブランチ操作もわかりやすく簡単です。特に、不幸にも衝突が起きてしまった場合の解決作業はびっくりするほど簡単になっています。この特長は、AIエージェントを使用したヴァイブコーディングとの相性がとても良いようです(筆者はあまり詳しくありませんが)。本記事では主に衝突解決に注目し、スカッシュはちょっとだけ出てきますがリベースについては触れません。
全体的に、バージョン管理システム(特にGit)のとっつきにくさ、怖さを解消し、その多大なメリットのみを提供しようという意欲を感じます。なので、バージョン管理システムというものにあまりよい印象がない人にこそJujutsuを試してもらいたいと思い、この記事を書いています。
Jujutsuは現在バージョン0.38.0とまだ1.0に到達しておらず、experimental(実験的)と表現されているように未完成なソフトウェアです。すでに日常の使用で問題に遭遇することはほとんどないくらいの完成度はあると感じていますが、まだまだ仕様変更などは頻繁に行われています。この記事でも可能な限り追従したいと思いますが、Jujutsuについて調べ物をするときはなるべく最新の情報に当たるようにしてください。
インストールと初期設定
では早速インストールしてみましょう。筆者はJujutsuのGitHubのReleasesページからバイナリをダウンロードして、パスの通っている場所にコピーしています。公式ドキュメントによれば各種パッケージシステムへの収録も増えてきているようですので、お好みでそちらもどうぞ。
現在のJujutsuはGitリモートリポジトリとの通信にgitコマンドをサブプロセス起動するようになっています。GitHubなどのリポジトリホスティングとやり取りをする場合はGitもインストールしてください。
インストールが終わったら、最低限の初期設定として、あなたの名前とメールアドレスをセットしましょう。
$ jj config set --user user.name "あなたの名前"
$ jj config set --user user.email "あなたのメールアドレス"
さて、ここからは筆者のおすすめ設定ですので無視して先に進んでいただいてもかまいません。環境変数EDITORなどでテキストエディターが自動的に立ち上がるようになっているのでしたら、以下のように実行すると設定ファイルが開かれるはずです。
$ jj config edit --user
以下のように追加するとログ中のツリー表示にUnicode文字ではなく、ASCII文字を使うようになります。
[ui.graph]
style = "ascii-large"
デフォルトではログ中のコミットメッセージの2行目以降を省略してしまいます。以下のように追加すると最後まで表示するようになります。
[templates]
log = "builtin_log_compact_full_description"
基本的な使い方
jj git clone
まずはGitリポジトリのクローンからやってみましょう。
$ jj git clone リモートURL
バージョン0.34.0から、JujutsuのコマンドもGitのコマンドも両方使える同居モードがデフォルトになっています。--no-colocateオプションを付けると無効にすることもできるようですが、Jujutsuはなんかだんだ言ってもまだ未完成のツールなので、同居モードにしておくことをおすすめします。
jj
Jujutsuにはデフォルトコマンドの概念があり、jj logが初期設定されています。なので、ログを見たい時は単にjjとタイプすればよいです。
$ jj
以下に出力例を示します。
Jujutsuでは履歴の1単位のことをチェンジと呼びます(詳細は後述)。それを指定するためのIDは2つあり、右側はGit由来のコミットID、左側はJujutsuのチェンジIDです。どちらも重複しないところまでで色が変わっており、そこまで入力すれば指定できるということがひと目でわかります。
なお、デフォルトのログ表示は他者の作業ブランチのような、ユーザーがあんまり興味なさそうなものは適当に省略する仕様になっています。全てを表示するには以下のように-rオプションを追加してください。
$ jj -r::
オプションで与えている::はリビジョンセット言語というもので、この場合は始めから終わりまで全てという意味になります。
jj new
修正作業の開始を指示するにはjj newコマンドを使用します。
$ jj new 起点のチェンジ
指定したチェンジの子供として新しいチェンジが作られ、そこを修正できるようになります。
jj desc
修正が落ち着いたら、そのチェンジに対してjj descで説明、いわゆるコミットメッセージを追加しましょう。
$ jj desc -m "修正の説明"
Jujutsuではコミットのタイミングとは無関係にいつでも説明を付けられるので、コミットメッセージと言うとなんかしっくりこないというのはありますね...
jj commit
実際のところは従来のバージョン管理システムでそうしてきたように、修正が一区切りついたらコミットメッセージを書いて、次の修正を始めるという使い方がほとんどだと思います。その場合はjj commitを使えます。
$ jj commit -m "修正の説明"
実はこのjj commit、jj descのあとにjj newを実行しているだけです。とはいえ大変便利なので筆者はこればかり使用しています。
パラダイムシフトを受け入れる
前述の通り、Jujutsuにはユーザーに発想の転換を促すような側面があります。それは決して導入障壁ではなく、こう作ってあればこんなに楽だったのか! という発見を伴うものだと思っています。ここでまとめて解説します。
addコマンドがない
作成したファイルはただちにバージョン管理対象になります。修正も自動的にコミットされます。
Gitみたいな修正したファイルのコミットを指示するためのaddならそりゃいらねーだろってところなんですが、SubversionやMercurialみたいな、ファイルをバージョン管理対象にするためのaddもないのは結構攻めた仕様だと思いますね... まあ実際特に困らないのでこれでよいのでしょう。.gitignore(見てくれます)だけ、ちゃんと設定してあげましょう。
作業コピーもコミットされている
Gitでは作業コピーは次のコミットを作るための場所であり、つまりそれは常にコミット前の状態です。一方Jujutsuでは、作業コピーも自動的にスナップショットを作成され続けている、つまり裏でコミットされまくっているという違いがあります。
このため最初のうちは、作業コピーも各種コマンドの操作対象として指定可能であるということに気をつける必要があるかもしれません。Gitでは暗黙の操作対象は最後のコミットであることが多いですが、Jujutsuでは作業コピー(リビジョンセット言語でいうところの@)であることが多いです。これは実はあまりうれしくないことも時にはあり、作業コピーの親(リビジョンセット言語で@-)を明示的に指定することも多いかと思います。このことは頭の隅に入れておきましょう。
ともあれこの設計により、急にほかの作業が入ってブランチを移動しないといけないような時にも、今の作業コピーを退避しないとなあ... みたいな心配をする必要はなくなります。だって裏で常にコミットされ続けているんですもの。
チェンジという概念
先ほど、作業コピーは裏でコミットされ続けていると言いました。ここで疑問が発生します。データのハッシュ値をオブジェクトIDとするというGitの仕様により、コミットIDも変わり続けるのではないかと。まさしく、コミットIDは作業中に変わり続けるため、Jujutsuではコミットをチェンジという概念でラップしています。そしてチェンジIDは裏でコミットが作られても変わりません。チェンジIDを使ってください。はるかに便利です。
ブランチ名はない、ブランチはある
ブランチ名の概念はありません。ツリーを眺めて、ここから修正しようかなというチェンジを指定してjj newを実行し、即修正を始めてしまってかまいません。チェンジを追加して伸ばしていけばそれがブランチになります。ブランチ名のことは忘れてください。そんなもんいらなかったということがよくわかります。
これにより、作業ブランチを伸ばしていたつもりだったのにmainブランチにコミットしていた、みたいな事故を起こすことはかなり難しくなります。
ブランチ名の代わりにブックマーク名
とはいえ、実際には作業ブランチをGitHubなどのホスティングに送り、マージ作業をする時がきっとやってきます。ここまでブランチ名なしでも平和にやってきましたが、Gitの世界では基本的にブランチ名が必要です。そこでブックマークを使います。
Gitの世界にブランチを公開したい時は、ブランチの先頭のチェンジに対してjj bookmark createでブックマークを作成してください。その後jj bookmark trackでリモートリポジトリとの同期を開始し、jj git pushでプッシュすれば、それがGitの世界ではブランチとして見えるようになります。
$ jj bookmark create ブックマーク名 -r 作成先のチェンジ
$ jj bookmark track ブックマーク名
$ jj git push
一つ気をつけなければいけないことは、ブックマークはあくまでも特定のチェンジを指しているものだということです。ブランチに新しいチェンジを追加してもブックマークは自動的に新しいチェンジに移動はせず、ユーザーが手動で移動してあげる必要があります。
$ jj bookmark move ブックマーク名 -t 移動先のチェンジ
$ jj git push
これをめんどくさいと感じるか、安全側に倒してあると感じるか... 筆者は後者ですね。
やや高度な使い方
マージ
Jujutsuでももちろんマージはできますが、mergeコマンドはありません。ではどうするのかというと、jj newコマンドで複数の親となるチェンジを指定することでそれらをマージしたチェンジを作ることができます。衝突がなければjj commitしておしまいです。
$ jj new マージ元のチェンジ1 マージ元のチェンジ2
$ jj commit -m "マージ完了の説明"
衝突解決
では、衝突がある場合はどうなのでしょうか。その場で直す場合はjj statusで衝突しているファイルが何かを確認後、該当ファイルを開いて衝突マーカーを見ながら修正、完了したらjj commitしておしまいです。
$ jj new マージ元のチェンジ1 マージ元のチェンジ2
$ jj status
$ (衝突を解決)
$ jj commit -m "マージ完了の説明"
実はJujutsuでは衝突を解決せず、残したままコミットすることもできます(というか、全てが常にコミットされているというコンセプトなのですから、衝突ありという状態も当然コミットされているわけですね)。この衝突あり状態でも他の衝突していないファイルであれば安全に修正できますし、コミットもできます。
しかし、いつかは辛い現実と向き合わなければなりません。覚悟を決めて衝突を解決していきましょう。衝突が始まったチェンジを指定してjj newを実行し、jj statusで衝突しているファイルを確認します。該当ファイルを開いて衝突マーカーを見ながら修正しましょう。
以下にその模様を示します。チェンジID oで発生した衝突をチェンジID nで解決しました。
その後jj squashでその修正を親のチェンジに反映します。以下にその結果を示します。
なんと! 子孫も含めてすべての衝突が解決されました。すばらしい! 全然覚悟なんかいらなかった。
アンドゥ
操作を間違えて、やりたかったことと違う結果になってしまうこともたまにはあるでしょう。そんな時はjj undoで元に戻せます。取り消したい操作が何でも実行するコマンドは一つ、jj undoです。そしてこのjj undoでは多段アンドゥもできます! 取り消しがやりやすいので安心して作業を行えます。
課題
冒頭に述べた通り結構仕様変更があります。毎月だいたい月初にマイナーバージョンアップが来る感じなので、それに合わせてチェンジログをチェックしておくとよいでしょう。新しいものが好きな人ならむしろ楽しんで追っかけしていけるのではないかと思います。
明らかに必要なのに未実装の機能もあります。ただし、実装は少しづつ進展しています。ここでは過去に例としてタグの作成ができないことを挙げていましたが、バージョン0.35.0でjj tag setが追加され、できるようになっています。Jujutsuでできないことも同居モードにしておけばgitコマンドでできるため、当面はそれでしのげばよいのかなとは思います。
GUIクライアントが成熟していないのも課題だと思います。個人的には"難解な挙動にリッチなGUI"と"明快な挙動にCLI"なら後者を選びますが、まあその辺は人それぞれですよね。もちろん、ナウでヤングなGUIクライアントはあったほうがよく、その登場に期待しています!
おわりに
と、ここまでJujutsuの推しポイント(と課題)について書いてきましたが、興味を持っていただけましたでしょうか。かなり内容を絞ったつもりでしたが結構長くなってしまいましたね...
Jujutsuの導入によりバージョン管理にまつわる煩わしさから解放され、創造的な作業に集中できるようになる、そのきっかけにこの記事がなれば幸いです!


