Git と GitHub の次を妄想する

2021/02/12に公開1

GitHub みたいなサービスを今一から作るならどの言語・フレームワークを使うか

GitHub の次は何かを考えてみるのは、現実に実現困難なのを忘れれば、なかなかに楽しいことではあります。ここではその妄想をやっていきましょう。

GitHub の抱える課題を分割すると、Git の問題と、 GitHub の提供する機能の問題に分けられると思います。自分は、Git をベースとして GitHub に勝つのは現代ではなかなか難しいと考えています。MS による買収と実際に注ぎ込まれてる資本を考えると、よほど斬新な切り口でないと、 同じ Git を使っても優位性は出せません。

なので、 GitHub に本質的に勝つには、その基幹となる VCS から考え直すとよいのではないか、と考えています。幸いなことに(?)、Git はその優秀さは認められていますが、学習の困難さや特定のユースケースで機能しないことが知られています。そのため現代に求められている機能から Git / GitHub に足りていない点を分析してみます。

Git / GitHub の良い点

  • CLI に最適化されたコマンド体系
  • 分散ファイルシステム / 高効率な圧縮処理(git pack)
  • Git のコラボレーション機能の不在を補う GitHub の存在

Git の課題

  • GUI ツールの決定版の不在
  • 部分的なチェックアウトができない
  • Git 自体のコラボレーション機能の欠如
  • バイナリの扱いが下手(ここは今回扱わない)

Git 自体の コラボレーション機能の欠如

例えば GitHub の pull-request 相当の機能が Git 本体にありません。

CLI の命令体系として GitHub の Pull Request や Review, Issue のようなコラボレーションを機能を織り込んでいったほうがいいのでは? と自分は考えていました。

ここに異論はあると思います。一つのことをうまくやる、という Unix 哲学において Git ほどうまくやれているツールは他にありません。ただ、merge や push のようなコマンド体系も、 PR を前提とした場合に変化があると思うのです。

Git GUI ツール決定版の不在

とくにプログラミングのためのツールにおいては、 GUI は CLI の写像となりがちです。Git の 操作体系は CLI においては直感的ですが、GUI においての操作が煩雑で、これをうまく表現できているツールがあまりありません。ステージング概念の存在と、ファイルの一部の add からの commit という操作を GUI 上の操作に落とすことが困難です。それはそれとして、自分は git add -p より便利なツールを知りません。

基本的に、 Git の世界観では Tier 1 に CLI での操作があって、GUI は常に CLI に従属するものなので、Git のトレーニングは CLI で行われます。GUI ツールの操作体系を覚えたところで、事情によってツールが変わると操作体系のほとんどを覚え直す必要があります。

CLI 操作体系を覚えることは、ファイルシステムの理解と、Unix コマンドの学習がセットになってきます。Git に限らずバージョン管理を遍く普及させたいという立場の人間にとっては、これが普及のブロッカーになっているような感覚があります。

部分チェックアウト / Sparse Checkout

Google や Facebook は社内で一つのモノレポになっていて、そのツリーを部分的にチェックアウトする社内ツールがあると聞いていますが、公開されていません。我々のような一般的な開発者のモノレポ開発は、ツールの不足により、困難を伴っている感覚があります。

Mercurial には Partial Clone があります。Facebook の実験的なプロジェクトとして、 Eden という Mercurial を Python から Rust に書き直すプロジェクトがあります。

今更 Mercurial を使いたいかというと、個人的には微妙な気持ちがありますが…。

一応、GitHub に Sparse Checkout の仕組みはあるのですが、使ってみるとかなり微妙な体験になります。

リポジトリの一部だけ checkout する Git コマンド:sparse-checkout - はんなりと、ゆるやかに

新しい VCS を設計するなら

まず、オンラインのコラボレーションを第一に設計されるべきだと思います。部分的にチェックアウトできること、スムーズにエディタと統合されること、あたりを想定します。

ちょっと Git の内部実装の話になるのですが、 Git の分散ファイルシステムでは、 .git/objects/[sha1] で自己署名を行うような構造になっています。つまり異なるリポジトリでも、ファイルの内容が同じなら、同じハッシュ値になります。これは非常に優れた仕組みで、sha1 をぶつけない限り、内容について嘘をつくことができません。自分の変更が誰かの手元と一致していれば、ネットワーク上から何が必要でな何が不要かを判別できます。手持ちのファイルのハッシュを交換することで、差分が明らかになって効率的な sync が可能です。

最近は Google の実験等により現実的な計算時間で sha1 をぶつけることが理論上可能であることがわかってるので、sha256 や別のブロックチェーン周りで採用されてる量子暗号耐性のあるハッシュアルゴリズムを採用すべきでしょう。

git の優秀さは、 個人的に git pack にあると思っていて、objects 内で似たような内容のチャンクを、編集距離に基づいて圧縮します。各 blob の中身は Packfile へのインデックスになります。

Git - Packfile

この blob object の仕組みはそのまま引き継ぎつつ、新しい VCS を考えると、今の Git はローカルの blob を git fetch/pull で定期的に sync する方式なのを、次世代のバージョン管理システムでは、ネットワークファーストで参照時にオンデマンドにも取得できる方式になるのではないでしょうか。

自分が今まで Web ベースのエディタを試作してきた経験だと、Git は初期化にルート要素からの参照ツリーを要求するのが、Web のペイロードに向いていません。ローカルのチェックアウトに時間がかかりすぎて、体験が非常に悪くなります。ブラウザもインメモリで大量のデータを抱えることを想定していないので、インメモリに大量のデータを乗せることで挙動が不安定になります。

部分チェックアウトを前提にすると、リポジトリの概念が変質します。GitHub のユーザー > リポジトリという単位は、単にネームスペースでしかなくなります。

blob objects を共有する P2P のネットワークでファイルを共有し、各自は自分が書き込み権限があるネームスペース下にファイルツリーを作成し、それらの実体は blob objects への参照になるでしょう。

…というのが IPFS Powers the Distributed Web に近い発想です。自己署名オブジェクトツリーの IPFS には IPNS という仕組みがあって、ハッシュに別名をつけることができます。

IPNS | IPFS Docs

何が出来て、何が困難になるか

つまり新しい VCS を考えると、「追記型のバージョン管理を持つ P2P ネットワーク」をバックエンドとした「ファイルシステム」として表現されるのではないでしょうか。このインターフェースとして、ハッシュへのエイリアスを操作する API があり、その上にディレクトリ構造がかぶさります。中央集権的なリポジトリを介さず、オンラインなユーザーの二者間で PR が作成できて、二者間で完結して Merge ができる、みたいなものです。

現状、GitHub の GUI からコードを変更することはあまり体験良くないです。これは、ファイル一つだけ開くかチェックアウトするか否か、みたいなトレードオフになってるからです。これを部分的にファイルをチェックアウトしてオンライン上のブラウザで開くみたいな体験にしたいと考えていて、既に似たようなものはあって、 github.com を github1s.com に書き換えると vscode online 上でそのファイルを閲覧できる github1s があります。

conwnet/github1s: One second to read GitHub code with VS Code.

ただし、この時には「検索」が困難になる問題がわかっています。ローカルにすべてのファイルを持ってないので、ローカル検索が機能しません。誰かがすべてのデータを集めて検索するシステムが必要になります。また、オンデマンドに blob を取得するために Network の RTT が挟まるので、深さに応じて IDE の解析も遅くなってしまいます。そのために 関連リソースの Preload も必要です。HTTP Header で Preload を指定する仕様などを工夫する必要があると思います。

https://www.w3.org/TR/preload/#example-2-using-http-header

https://blog.jxck.io/entries/2016-03-04/preload.html#header-での指定

IPFS 使ったファイル IO を作ってみると、そこまで体験が良くないことがわかります。これは P2P の宿命である、人気がないファイルは遅く、またすぐに消えてしまう現象です。なので、 GitHub のような安定した体験を求めると常設された Peer Node としてファイル実体を常にホストし続けるサーバーをデプロイして置く必要があるでしょう。

この blob オブジェクトをすべて保持して、blob を収集する過程で検索インターフェースを提供するものが、次世代の GitHub になるのではないでしょうか。また、ネットワークに乗せるデータの質によっては暗号化も必要になるでしょう。

中央管理の場合は Cloud BigTable のような巨大なデータを扱える高速な KVS で blob storage を実現するか、 P2P の分散ファイルシステムで問い合わせる、といった実装になるでしょう。

また、ファイルの自己署名方式は Deno のようなネットワークからリソースを解決する言語のバックエンドに向いています。ハッシュの改竄が困難なため、一度安全性が保証されたスクリプトが、悪意あるユーザーに乗っ取られることはありません。というか自分は deno にその懸念をずっと持っています。同じ問題意識の人がやってるプロジェクトで、blockchain 上で改竄不可能な状態でコードをホスティングする nest.land というサービスが存在します。

nest.land

思考実験は楽しい

実際にこれを作ろうとすると、大量にスクラッチする必要があることがわかります。盛り上がりますね。

これだけだと課題に述べた Git GUI 決定版がないとか諸々の問題は解決してないのですが、下回りにはなるんじゃないでしょうか。

お金を出してくれる人がいたら作りたいですね。これ以上は疲れたのでそのへんで。

Discussion

Tsuyoshi CHOTsuyoshi CHO

一応、GitHub に Sparse Checkout の仕組みはある

Gitのコマンドの一部で、GitHubではないと思いますが。