JujutsuでGitの厳格さによる疲労を克服する
多くの開発者にとって、理想的なプルリクエストは、整理された物語のようなものです。型定義から始まり、データベース関数へと進み、UIで終わるという、レビュアーを導くための論理的でアトミックなコミットの連続です。しかし実際には、開発の真っ最中にこの「厳格さ」を維持することは非常に疲弊します。
私たちの多くは、「混乱したコミット(mayhem commits)」というパターンに陥りがちです。機能開発、バグ修正、リファクタリングがすべて混ざり合い、いくつかの乱雑なチェンジセットに積み重なってしまいます。これを整理するために git rebase -i や jj absorb といったツールが存在しますが、それらはマージコンフリクトや不正確な変更の割り当てといった、独自の摩擦を生じさせることがよくあります。これは「Gitの厳格さによる疲労(git rigour fatigue)」として知られています。複雑な技術的問題を解決しながら、同時にクリーンな履歴を保とうとすることによる精神的な負担のことです。
「洗濯物の大きな山」ワークフロー
この疲労に対抗するために、Jujutsu (jj) を使用した、よりリラックスしたアプローチを採用できます。Jujutsuは、ワーキングコピーを第一級のコミットとして扱うバージョン管理システムです。開発の最中に完璧な履歴を維持しようとする代わりに、このワークフローでは、あえて乱雑な状態を受け入れ、最後に一気に片付けることを提案しています。
プロセス
- 混乱を受け入れる: 機能開発を通常通り行います。即興的なコミットを作成し、一時的なデバッグ状態を含め、特定の変更がどこに収まるかを気にしないでください。おそらく、乱雑で重複する一連のコミットが出来上がるでしょう。
- 理想的な状態を定義する: 機能が完成したら、理想的な履歴の「スケルトン(骨組み)」を作成します。
jj newを使用して、自分が欲しかったはずの記述的なタイトルを持つ空のコミットを作成します(例:「define types」、「add DB functions」、「server CRUD」)。 - 混乱をまとめる: すべての実際の開発コミットを、単一の「すべてを含むコミット(everything commit)」に squash(集約)します。
- 変更を分配する:
jj squash -iを使用して、「すべてを含むコミット」から理想的なスケルトンのコミットへ、対話的に変更を移動します。まず「赤」の変更(型)を選び出し、型用のコミットへ移動し、次に「青」の変更(UI)をUI用のコミットへ移動するといった具合です。
このプロセスの終わりには、「すべてを含むコミット」は空になり、履歴はレビュアーにとって完璧に構造化されたものになります。
なぜこれが従来の方法より優れているのか
jj split や標準的なインタラクティブ・リベースと比較して、この「洗濯物」メソッドにはいくつかの利点があります。
- コンフリクトのリスク軽減: 最終的な安定した状態から新しい履歴へと変更を移動させていくため、開発中に繰り返し
jj squash -iを使用した際に発生しがちな、中間段階でのマージコンフリクトを避けることができます。 - 認知負荷の低下: コーディングのフローに入っている最中に、どのコミットにどの変更が属するかを判断する必要がありません。「仕分け」作業は、最後に一度だけ行えばよいのです。
- 柔軟性: 他法の履歴のシーケンスにどう影響するかを気にせずに、単純な変更の塊(hunks)を最初に仕分けすることが容易になります。
トレードオフと反論
他のワークフローと同様に、このアプローチにも欠点があります。主な懸念は、中間コミットがコンパイルできない可能性があることです。もしチームがPR内のすべてのコミットがCIを通過し、ビルド可能であることを要求する場合、この方法は採用できないかもしれません。論理的なカテゴリに基づいて仕分けを行っているため、時系列的な依存関係ではなく、論理的なカテゴリに基づいて仕分けを行っているためです。
このトピックに関するコミュニティの議論では、「優れたコミット(Good Commits)」の価値についてのより広範な議論が浮き彫りになります。
「クリーンな履歴」を支持する意見
"Jujutsuの、ワーキングコピーをコミットとして扱うアプローチは、Git rebase ワークフローにおける多くの一般的な摩擦を解消します。" — @danborn26
これらのユーザーにとって、VCSを物語を伝えるためのツールとして扱う能力は、レビュープロセスを大幅に効率化します。
「Squash and Merge」を支持する意見
逆に、一部の人々は、チームがマージの際にPR全体を一つのコミットに squash してしまうのであれば、完璧な履歴を構築するための労作は無駄であると主張します。
"ついにPRをsquadashしてマージする方式を採用し、素晴らしいコミットを書こうとすることに若さを費やしたことに気づきました。" — @drdrey
また、完璧にクリーンな履歴は、設計がどのように到達されたかという進化の過程(コンテキスト)を削ぎ落としてしまうため、実際にはデバッグにおいてより役に立たない可能性があると指摘する人もいます。
最終的な考察
Gitを使うかJujutsuを使うかにかかわらず、目標は、コードを書くことと履歴を記録することの間の摩擦を低減することです。最初からアトミックなコミットの規律を守ることを好兼む人もいれば、squash による履歴の完全な消去を好む人もいますが、「洗濯物の大きな山」アプローチプローチは、中間地点を提供します。作成中は乱雑でも自由であり、後で物語をストーリーとして整える力を持てるのです。