4 ポイント 投稿者 GN⁺ 2023-08-02 | 2件のコメント | WhatsAppで共有
  • Jujutsu は、ソフトウェアプロジェクトのコードのコピー、変更の追跡、変更の公開に使うバージョン管理システムであり、新規ユーザーと経験者、個人の新規プロジェクトと大規模な履歴・チームの双方を考慮して、使いやすいように設計されている
  • ユーザーインターフェイスとバージョン管理アルゴリズムを、コンテンツを提供するストレージシステムから内部的に分離しており、現在は Git リポジトリをストレージ層として使用することで、Git ベースのツールと互換性がある
  • Git にはコミットとファイルのみが保存され、bookmark(branch)やその他の上位メタデータは Git の外部にあるカスタムストアに保存される
  • デフォルトの Git バックエンドは gitoxide Rust ライブラリを使用し、Git リモートリポジトリから branch を取得してリモートへ push でき、通常の Git コミットのように見えるコミットを生成する
  • 作業コピーを実際のコミットとして表現する working-copy-as-a-commit モデルを採用しており、ファイル変更は通常のコミットとして自動的に記録され、その後の変更ごとに amend される
    • dirty working copy が原因でコマンドが失敗しない
    • git stash が不要
    • 作業が終わる前でも、作業コピーコミットにコミットメッセージを設定できる
  • リポジトリ上のすべての操作は、操作後のリポジトリ状態のスナップショットとともに記録され、以前のリポジトリ状態の復元、操作単位での undo、最新ではない特定操作の revert が可能
  • コンフリクトをコミットと同じ第一級オブジェクトとして記録し、コンフリクトが発生した操作も成功扱いとなり、その後は単一のコンフリクト解決ワークフローで処理できる
  • コミットを修正すると、既存コミットのすべての descendant が新しいコミットの上に自動的に rebase され、コンフリクト解決結果も descendant に伝播し、rebased コミットを指す bookmark と作業コピーも更新される
  • 明示的な index や staging area はなく、commit の選択には revset 言語を使用し、出力フォーマットはユーザーが設定可能な template 言語で処理する
  • 履歴書き換え機能として、任意のコミットのメッセージを編集する jj describe、チェックアウトせずにコミットの変更を編集する jj diffedit、コミット分割用の jj split、変更の一部を別のコミットへ移す jj squash -i --from X --into Y を提供する
  • 安全な同時複製機能は実験的機能であり、Dropbox・rsync のような分散ファイルシステムまたはバックアップツールを使う場合にリポジトリが破損状態にならないよう設計されており、最悪の場合でもローカル状態とリモート状態の間のコンフリクトを露出させることを目指している
  • jj は実験的なバージョン管理システムであり、Git 互換性は安定しているものの、開発中の機能、最適とはいえない UX、特定の利用方法におけるワークフロー上の空白が存在する可能性がある
  • 機能はかなり完成しているが、Git submodule のサポートはまだ完了しておらず、複数の性能バグがあり、メールベースのワークフローのネイティブサポートはない
  • 1.0.0 より前には、ワークフローの変更やオンディスク形式の後方互換性のない変更が予定されており、形式変更については透過的なアップグレード、または要求時に使えるアップグレードコマンド・スクリプトの提供を試みる
  • Apache 2.0 ライセンスのオープンソースソフトウェアであり、Google のサポート対象製品ではなく、サポートはコミュニティによって提供される

2件のコメント

 
xguru 2023-08-03

Jujutsu - シンプルで強力な Git 互換 DVCS

私が1年半前に投稿したものですが、またHNで話題になっていますね。

 
GN⁺ 2023-08-02
Hacker News の意見
  • ここに上がっていてうれしい。2〜3週間前くらいに jj に乗り換えたが、戻るつもりはない。頭の中の作業スタイルはかなり変える必要があったものの、jj が提供するフローはかなり気に入っている
    何をコミットするかを別途考える時間がなくなり、すべてのファイル変更が自動的に作業コピーのコミットに反映される。もちろん望ましくない場合もあるので、コミットを2つに分けたり移動したりする機能があり、すべての操作がコミットを対象に動作する点が良い
    jj log は複数ブランチの全体図を見るのに優れていて、コンフリクトは一部だけ解決してから別のブランチへ移動でき、短縮された changeset ID も便利。たとえば jj log でリベースしたい changeset を見て、jj rebase -s qr -d master のように実行できるので、ブランチ名を全部打つより速い

    • 誤ってシークレット値が入ったファイルを保存して、自動的に取り込まれてしまったらどうなるのか気になる
    • 普通に GitHub リポジトリと一緒に使うものなのか気になる
      Dropbox のようなバックエンドと使えると書かれているが、IPFS と簡単に使えるシステムが出てくるとよさそう。大容量データでは GitHub に 1TB を保存できず、LFS は有料なので除外して考えている
      データセットを使おうとする人はどうせローカルに持っているので、ダウンロード元が1つではなく数千になる IPFS は自然な解決策。データストアに IPFS を使うならすぐ乗り換えるが、そうでなければ調べる価値はあまりないと思う
    • チームでうまく使っている事例があるのか気になる。2人が同じブランチで作業するとどんな感じなのか知りたい
  • Jujutsu は作者の個人プロジェクトとして始まり、今では Google で作者のフルタイムプロジェクトになっている。Git Merge 2022 で発表されたことがある
    Jujutsu: A Git-Compatible VCS - Git Merge 2022:
    Video:
    https://youtu.be/bx_LGilOuE4
    Slides:
    https://docs.google.com/presentation/d/1F8j9_UOOSGUN9MvHxPZX...

    • 個人プロジェクトが Google でフルタイムプロジェクトになったというのは、かなり誇らしいことだろう
  • ほぼ1年にわたって jj を毎日使ってきたが、Git のユーザー体験より明らかにずっと良いと思う。変更をアトミックなコミットに分けることに神経を使うタイプなので、自動リベースが中核機能になっている
    コンフリクトをコミットに記録できるため、Git や Mercurial のようにリベースの途中で止まってコンフリクトを直す必要がない。コミットを修正したり削除したりしても、jj がすべての子孫コミットを自動でリベースしてくれ、Git rebase と違って Mercurial evolve のように複数の子も処理する
    コミット履歴を扱う基本コマンドも良い。jj move|restore であるコミットの変更を別のコミットへ移動またはコピーし、jj split でコミットを分割し、jj rebase でコミットを移動する。作業ツリーやインデックスなしに、すべてがコミット履歴の中にあるので、同じコマンドとフラグで処理できる
    作業ログも素晴らしく、ほとんどの作業を問題なく元に戻せる。Git で悪い rebase や commit --amend を直そうとすると、reflog から該当するコミットを探し、ref を手動で直さなければならないのとは対照的
    一番不便なのは、自動作業コピーコミットが望まないファイルまでコミットしようとすることがある点と、リネーム検出がないためマージを Git ほど上品に扱えない点。それでも壊れたコミットは jj split|restore で比較的簡単に直せるし、jj の開発者たちもリネーム問題に取り組んでいる

  • 作業結果としてコンフリクトが出ても、その情報をコミットに記録して作業自体は成功させ、あとでコンフリクトを解決できるという点がうれしい。ここ10年ほど協調編集アルゴリズムを扱ってきており、理想的には Git のようなツールが最終的に CRDT ベースのアプローチに置き換わるといいと思っている
    CRDT を使えば同じツールでペアプログラミングができ、Git で起こり得る自己コンフリクトのような複雑なマージもよりうまく扱える。より強力なモデルでもある
    ただし現代のテキスト CRDT は同時編集を自動的にコンフリクトなしで解決するが、オフラインでコード共同作業をする場合は、通常はコンフリクトが明示されて人間が直接解決することを望む。CRDT は Git より編集履歴の情報を多く持っているので理論上は可能だが、きちんとやるにはコンフリクト自体をテキストファイルのデータモデルに入れる必要がありそうで、現代のエディタとどう噛み合うのかはよく分からない
    jj が同じコツを見つけたように聞こえるので、実際にどれほどよく動くのか期待している。CRDT ベースのコードリポジトリという夢に一歩近づいた感じがする

    • Pijul を見てみるとよさそう。ここで述べたことの大半を実質的に実装している。Pijul は CRDT であるパッチの上で動作し、コンフリクトを第一級の概念として扱う
    • git bisect に価値を感じたことがないのか気になる
      再現可能なバグがあり原因が複雑なら、どのコミットがバグを持ち込んだのかを見つけて、どの変更が原因かを見るのは有用ではないかと思う。少なくとも何を直すべきかの最初の手がかりを得るには良い
      現在の git bisect は、すべてのコミットがビルドおよび実行可能なときに最もうまく機能する。コンフリクトマーカーが入っていてビルドや実行ができないコミットがあると、はるかに多くの手作業が必要になる
      このようなシナリオで、git bisect に相当する機能をどう適応できるのか気になる。単純にコンフリクトマーカー文字列をスキャンするのは適切ではないかもしれない。ドキュメントでコンフリクトマーカーを説明していたり、ある種のマークアップ言語では ======= が下線として合法的に使われたりするためだ
    • 実際にはどう展開するのか気になる
      ソース管理履歴は意味のある成果物であり、パッチの束は開発マシンを離れる前に、漸進的でアトミックな変更の連続として整理されるべきだという考えと衝突するように見える
      ただ、周囲の開発者の大半はすでに Git の履歴を無限のエディタの取り消し履歴のように扱っているので、このアプローチはその事実を固定化してしまう気もする
      長期的な履歴がどのように機能すると見ているのか、今より有用になるのか、それとも有用でなくなるのか気になる
  • 作業コピーが自動コミットされるというのは最初は良さそうに見えるが、好ましくない状況が多い。
    新しい生成物ファイルができたのに、まだ .gitignore に入れる前だと自動コミットされるし、あるブランチで無視ファイルを追加してから別のブランチに切り替えると、作業コピーには残っているが .gitignore にはないため自動コミットされる可能性がある。
    それに、後からコミットを分割するより、一部のファイルだけをステージングしてコミットするほうがずっと簡単。

    • 一部のファイルだけをステージングしてコミットするほうが、後でコミットを分割するより簡単だという通念に、このプロジェクトは挑戦しているのだと思う。
      自分もその考えが頭に染みついているが、本当に正しいのかは分からない。実際には、インデックスを直して後からコミットを amend することはかなり多いし、事前にやることもできる。
      どうせ事後編集を完全には避けられないなら、そうした編集のための単一のワークフローのほうが良いのではないかと思う。まだ使ってはいないが、当たり前だと思っていた慣習が実は役に立っていないかもしれない、という点をかなりもっともらしく突いているアプローチに見える。
    • 同感。普通、プロジェクトディレクトリには出力ファイル、メモ、一回限りのスクリプトのような追加ファイルが10個以上ある。コミットにファイルを入れるときは常にファイル名で選ぶのであって、新しくできたものや変更されたものをすべて入れるわけではない。
      生成・変更されたすべてのファイルが常にコミットに入るようなユースケースは自分にはない。
      別のブランチに切り替えたとき、ファイルが作業コピーに残るのに .gitignore にはないというのは、Git の失敗だと思う。.gitignore に加えて .local.gitignore のようなものがあるべきだ。自分にだけ必要な無視ファイルはとてもよくあり、プロジェクトの .gitignore に入れる性質のものではない。方法はあるがどれもぎこちないので、デフォルトで簡単に提供されるべきだ。
    • 最初の問題は、すでに追跡中のファイルと新しいファイルを簡単に比較できればよいのではないかと思う。
      それでも興味深い。Git のステージングを好きだったことはないが、ここで言われているケースは経験したことがなかったので、ファイルシステムとコミットの間に中間段階が必要なのだと今になって理解した。
    • README を読んだ限りでは、そうしたファイルを .gitignore に追加すると、次の自動コミット時に匿名の作業コピーコミットから再び外れる仕組みだと理解している。
      ファイルがそもそも追加されないのではなく、匿名の作業コピーコミットに入ってから外れるという流れは直感的ではないが、その匿名コミットがほとんどのユーザーに見えないなら差はなさそうだ。
    • こうしたことがjj の設計でなぜ問題になるのかよく分からないし、一部のファイルをステージングすることが、後でコミットを分割するよりなぜ簡単なのかもよく分からない。
      ドキュメントを見ると、懸念しているいくつかのケースは明示的に扱われている。
      https://github.com/martinvonz/jj/blob/main/docs/git-comparis...
  • いくつかの特殊な場合を除けば、ここ数年コマンドラインで Git をほとんど使っていない。日常的には IntelliJ のようなIDE 内蔵の統合機能に頼っていて、なぜわざわざ手作業で苦労するのか理解しにくい。
    エディタ内で行単位に選んで部分コミットできるし、すべてのブランチを見て、マージや cherry-pick をし、コミットや amend をし、更新を pull し、タグを編集する、といったことをショートカット一発で処理している。
    ただ、ここでは自分は少数派のようだ。Git は必須スキルで、本物のプログラマーなら目をつぶってでもコマンドを打てるべきだ、というような雰囲気まで考えるとなおさらで、なぜなのか気になる。

    • 自分は常にバージョン管理システムはコマンドラインで扱うのを好んできたし、これからもそうするつもりだ。
      このスキルは環境を選ばないので、リモートマシンに接続してリポジトリを見るのもローカルと同じだし、エディタごとに VCS 連携のやり方を新しく覚える必要もなく、慣れたツールをそのまま使える。
      例に挙げられた作業はコマンドラインでも同じくらい簡単にできるので、エディタ統合が特別だとは思わない。reflog を触るような変わった高度な作業が必要になれば、結局コマンドラインを取り出すことになる可能性が高い。
      もちろん GUI を使う人に不満はない。道具で生産的になれているなら判断することではないが、なぜかと聞かれたので答えただけで、自分のやり方のほうが優れていると主張しているわけではない。
    • IDE 統合は通常、Git CLI の全機能を実装していないという経験がある。改善されているかもしれないが、基本的な clone/branch/commit/merge を超えて、開発者やブランチが少し増えるだけで、結局トラブル解決には Git CLI に戻ることになった。
    • 本物のプログラマーかどうかは分からないが、Git GUI が間違ったことをするかもしれないという不合理な恐れがある。IntelliJ でも Git は内蔵 CLI を開いて扱っている。古い習慣はなかなか消えない。
    • Git を使い始めたばかりの多くの人は、Git がどう動作するのか、つまりコミットとブランチが何で、何ができるのかを理解していない。そのうえで CLI ツールのせいにし、GitHub Desktop を使えばすべて理解できるはずだと期待する。
      人々が「Git CLI を学ぶべきだ」と言う最も一般的な文脈はこの場合だ。
      数日前にも、Git コマンドを覚えたくないので GitHub Desktop を使おうという例があった: https://www.reddit.com/r/learnprogramming/comments/15b7pra/s...
    • チームで Git を理解している人は2種類しかいない。CLI を使う人と、Git を理解しないままボタンを押し始める人だ。
  • Git 互換性を前面に出すアプローチのおかげで、Jujutsu はこれまで見たものの中でも Git の代替候補としてより有力に見える
    Git 互換性の説明を読んで気になったのは、Jujutsu ユーザーが GitHub などにホストされた Git リポジトリへ jj でアクセスするユースケースに主に焦点を当てているように見える点。逆に、ネイティブな Jujutsu リポジトリへ Git でアクセスする方法もサポートしているのか気になる
    ほとんどの開発者はすでに Git CLI に慣れているので、実運用では同じコードベースで jj と Git を併用する開発者が出てきそう。あるいは現実的な運用シナリオとしては、両方の CLI からアクセスするために、常にネイティブな Jujutsu データベースではなく Git をバックエンドリポジトリとして使うのか気になる

    • README の脚注によると、現時点では ネイティブバックエンドを使う実質的な理由はほとんどない
      このバックエンドは主に、後で Git バックエンドには簡単に追加できない機能を入れられることを保証するために存在している
    • 常に Jujutsu を Git リポジトリのフロントエンドとして使うか、完全な Jujutsu ベースのリモートリポジトリを使うことが想定されているのだと思う
      すでに Jujutsu を使っているプロジェクトで作業して貢献するなら、プロジェクトが自分のワークフローに合わせるのではなく、自分がプロジェクトに合わせるのが合理的
  • Git 互換性優先のアプローチのおかげで、Jujutsu はこれまで見た Git 代替候補の中でもより有力に見える
    コンフリクト管理が気になる。pmeunier が Pijul のためにパッチ理論を形式的に整理することにかなり力を入れていたのは知っているし、健全でない、あるいは問題のあるパッチやコンフリクトの概念は大きな問題につながり得る。Darcs の性能問題はそうやって生じたのではなかったかと思う
    リポジトリ Wiki の比較ページが、Pijul のコンフリクト処理は「似ている」という程度より、もう少し詳しく説明してくれるとよい

    • ここにもう少し詳しい説明がある: https://github.com/martinvonz/jj/blob/main/docs/technical/co...
      このような方法でコンフリクトを記号的に保存すると、後でコンフリクトを再現したり、特定のコンフリクトを自動解決したりもできるが、実際のコンフリクト内容そのものを解決する問題までは扱わない
      誰かが実装するなら、Pijul を jj のバックエンドとして使って両方の長所を得ることもできそう
  • rsync、Dropbox、分散ファイルシステム経由で 安全に複製できるとはいい。最近はだんだん、単純な同期と相性のいいシステム寄りになっている
    どこにでも、どんなツールで放り込んでもそのまま動くからだ。新しいツールがこういう方向を取るのはいつでも歓迎

    • この部分をもう少し説明してもらえるとうれしい
      こういう問題があるとは聞いたことがあるが、自分では直接経験したことがない。Git と rsync/Dropbox のようなツールの間でどのような 競合状態が起きて問題になるのか気になる
  • 作業コピーが自動的にコミットされるとはありがたい。ずっと前から必要だった機能だ
    エレガントなツールを作るために尽力した Martin に拍手を送りたい