Getting started with jj

Ellie Huxtable

jj入門

ここ数週間、jjを使っている。触ってみたのは初めてではないが、今回初めて定着した。

ここ数年、自分のgitワークフローはブランチの上で「変更を加えたらgit commit --amend --no-edit && git push --force-with-leaseする」というものだった。これでリモートをほぼ遅延なく最新の状態に保てていた。PRはコミット数が少ない、たいてい1つになるようにし、できるだけ小さく保つようにしていた。

エージェントと一緒に作業するようになってから、ブランチを切り替える頻度がぐっと増えた。そのせいで、git stashするか、変更同士が干渉しないようにしょうもないWIPコミットを作るかしなければならなくなった。

そこで登場するのが新たなヒーロー、jjだ。こちらのモデルは少し違う。巨大なマニュアルは書かない。すでにたくさん存在するし、どれも自分が思いつきで殴り書きするメモよりよっぽど出来がいい。

とにかく、一番気に入っているのは変更が常にコミットされることだ。編集するたびに最新のコミットが自動でamendされ、pushすればリモートを上書きする(jjの言葉で言えば「横に」動かす)。

changeの編集も簡単で、checkoutやrebaseであれこれする手間がない。まるで自分の好きなgitワークフローをそのままツールにしたかのようだ。なぜこれに気づくのにこんなに時間がかかったのか、自分でもわからない。

本当にただの殴り書きだ。もっと学んだら、またメモを公開すると思う。

ワークフロー

変更を加えるときのワークフローはこんな感じだ。

jj new main



jj describe -m 'feat: something really cool'
jj git push -c @

これで完了。PRをマージして、繰り返す。

jjではコミットよりもchangeという言葉を使う。changeは常に進化し続けるコミットだ。そして「@」は現在のchangeを指す。

新しいchangeを始める

作業を始める前に、changeを開始しよう。これから行う編集はすべてここに入る。

jj new main

これはmain(bookmark「main」が付いたコミット)の上に自分のコミットを作る(changeとcommitの違いは実際にあって、最初のうちは混乱する)。現在のchangeの子として新しいchangeを作りたいなら、単にjj newを実行すればいい。

changeに説明を付ける

ステージングエリアに変更を追加してからメッセージを付けてコミットする、という流れに慣れているだろう。jjでは変更はすでに追加されている。ただ、changeにはまだ説明(コミットメッセージのようなもの)が付いていないはずだ。

jj describe -m 'hello i am a message'

changeを作るときに同時に説明を付けることもできる。

jj new -m "hello i am a message"

コミットを新しいブランチにpushする

changeの上で作業していて、出来に満足し、GitHubに上げてエージェントに自分の(Claudeの)コードをこき下ろしてもらいたいときは?

簡単だ。

jj git push -c @

要するに「gitを使って現在のコミットをpushする」という意味だ。自動でブランチが作成され、リモートにpushされる。変更を加えながら何度でもこれを実行でき、jjの魔法が自動でgit amendとforce pushに変換される。

とはいえ、jjが独自のプロトコルとホストを持つ日が来るのが楽しみだ。

コミットを編集する

既存のchangeに戻って編集したいときも簡単だ。

jj edit 

このあたりからjjが本当に強力に感じ始めるし、同時に、これまで当てはめようとしていたメンタルモデルが崩れ始める。checkoutやrebaseなどでごちゃごちゃやる必要がない。

jjにはchangeとcommitの両方がある。ステージングエリアを持つ代わりにコミットが常に入れ替わっていくことを思い出せば、changeは安定したIDで、commit IDは編集のたびに変わるものだと考えられる。

元に戻す

jjで行ったほとんどの操作はop logに保存される。何かやって失敗しても、jj undoが助けてくれる。

その他のgit関連

jjは今のところ、ほぼgitの上に乗っかって動いている。既存のリポジトリを変換するのも、GitHubと連携するのも簡単にできるようになっている。

# Create a jj repo inside of a git repo
jj git init

# Fetch from the remote (github etc)
jj git fetch

# Push
jj git push

# Clone
jj git clone

で、ブランチはどこ?

ない! 少なくとも慣れ親しんだ意味でのブランチはない。jjでは「bookmark」を使う。これはコミットに付けられる文字列だ。changeをpushすると、自動でbookmarkが作られる。たとえばpush-refrefrefのように。

# bookmark the current change with a name
jj bookmark create 

# move a bookmark to a new commit
jj bookmark set  -r 

# other things exist just use --help

一番もどかしいのは、新しいchangeを作ってもbookmarkが動かないことだ。

用語集からの引用だ。

Gitとは異なり、「現在のbookmark」という概念はない。新しいコミットを作ってもbookmarkは移動しない。ただし、コミットが書き換えられた場合はbookmarkは自動で追従する。

リベースや編集、その他楽しいことについては、また今度書く。


余談:これをVimで書くのがめちゃくちゃ面倒だった。jj<esc>に割り当てているからだ。

原文は Ellie Huxtable により に公開されました。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。