UXエンジニアになりたい人のブログ

エッチだってしたのにふざけんなよ!

Gitは人類には早すぎる

3行まとめ

Gitは、思慮浅い下々のわれわれがしょうもないシステムの変更とリリースを管理する、というシンプルな目的に対しては難しすぎる。

特に妥当なマージ戦略がひとつに定められないことが致命的すぎる。

PullRequestのメリットだけを享受できるシンプルなSCMが出てきてほしいな。

 

ローカルリポジトリがファイルシステムで表現されるというわかりにくさ

えっそんなところから?という声が聞こえてきそうだが、そんなところからなのだ*1

 

この基本的なとこでつまづくひとはかなり多いし、その場合の説明が超面倒くさい。

PCを理解しているほとんどの人にとってファイルシステム上のファイルこそが永続的なもので「裏に謎の仕組みが潜んでいて永続的であるはずのファイルがコロコロ切り替わる」というモデルには馴染まないのだ。天才たちはすぐに新概念を理解できるかもしれないが、凡人は既成概念に囚われるのだ。ファイルは虚像で、本体は.gitの中にしかない、なんていうまどマギみたいな話はビビるのだ。

zipファイルをダウンロードしてフォルダに解凍するように、リポジトリをcloneしてフォルダにcheckoutできるようにすればよかった。フォルダとブランチが1対1のほうが全然よかった。フォルダの数=ローカルリポジトリでの展開ブランチ数となったほうが全然わかりやすかった。

しかも、ワーキングフォルダ内のファイル群が完全に切り替わるならまだしも、git add前のファイルは継続配置され続けるところが更に誤解を生みやすい。ローカルで保存しといたはずのファイルが消えちゃいましたとかって悲劇が生まれる。

最初のつまづきだけならまだしも、この辺の仕組みが実は理解できてなくてなんか起こるたびにcloneからやり直す、みたいな人も一定数いるように思う。

 

もちろん、現状のモデルもデフォルトでディスク利用量が少なくなるなどのメリットはある。毎日数十もの新ブランチを確認しなければならないなら速度的メリットも大きい。しかし、そういうのはオプション化してマニアックな人だけが使えば良いとおもうのですよ。 

 

ツリーが見れねえ

f:id:uxlayman:20210823152035p:plain

https://www.atlassian.com/ja/git/tutorials/using-branches

Gitブランチの解説文にはたいてい上のような図が載っているが、こういうきれいなツリーを表示するツールがない。

ほとんどの開発者はメインブランチdevelopから分岐したfeatureの担当であり、developとfeatureの状況を同時に見たいはずだ。developを幹として、featureを枝として。大抵の場合たくさんのブランチが並行しているのでブランチを絞りたい。大抵の場合たくさんのコミットがメインブランチに行われているので分岐近辺以外は省略してみたい。

できない。なんでや。

 

いまんとこ一番理想に近いのはVS Code拡張のGit graphかな?ほとんどのツールはなぜか2つのブランチだけに絞って表示することすらできない。

Gitはややこしいのでさまざまな状況でツリーを表示させて自分の意図通りの構造かを確認したくなるはずだ。あまり理解していないならなおさら実地で確認すべきだ。でもその構造をいい感じに確認するツールが少ない。

かくしてGitのブランチ構造を深く理解する術は失われ、いつまで経っても、〜なんとなくコミット・プルリク・競合で大慌て〜の状況は繰り返される。

 

マージするまでどれが競合するかわからなくて(※)競合状態をとりあえずもとに戻すのが大変(※)

  • マージしてみないと競合するかわからないので(※)、とりあえずマージする
  • マージして競合モードになるけど直せない(※)
  • なんとか競合を解除して、いざpushしようとすると↑18とかでてて、ええ?18回もコミットしてないのに大丈夫か?と不安になる
  • なんとか競合を解消したつもりでいても、GitHubでマージできる状態になってるかローカルでは確認できない(※)

こんなふうにして大混乱する。実際は※ついてるところは間違いなんだけど、詳しい知識がないと対応できない。

で、一番ヤバいのは、マージ作業自体はほぼほぼコード作成者本人しかできない、ってとこ。誰かがヘルプしたとしても、ここ変えた?変えてない?って考えてどっち採用するか決めるのは本人しかできない。詳しい人が巻き取ることはできない。マージの競合なんてしょっちゅう起こる作業のたびにこういうことで混乱する。

どうにかならんものか。競合を起こさないような運用*2みたいな意味不明なルールを決めることとかもある。うそぉ?と思うかもしれないけど、マジです。

 

解説がコマンドばかり/いいGUIツールがない

こう書くとマウント野郎がCLI使えないやつは素人、とか言いだしそうだが素人だしこんなもののプロになりたくないので放っておいてください。ていうかGitをCLIだけでやるって実用上可能なの?diffとかつらくない?

 

で、決定版のツールが全然ない。一番まともでマルチプラットフォームなのはSourceTreeか?でもまだ不十分。

ツールによって翻訳が入ったりコマンドとの対比内容が違ったりで同じことが違う表現になっててわかりにくいことこの上ない。

結局求められるのはツリーの見やすさと競合解消のしやすさだが、決定版がない。Windows民はトータスGitしか使えないこともおおい。ググればコマンドばかりで自力で成長できない。

そもそも、もとはといえばgitコマンドの構成がわかりづらいのが原因の部分も多いので将来にわたって改善しなさそうなとこがつらい。

 

(重要)マージ戦略問題

今までの話は、単に勉強不足だと言って切り捨てることができるだろう。

しかしこれは違う。宗教論争だ。一般にmerge vs rebase論争と言われている?のかな?知らんけど。ただしこれはmergeとrebaseだけの話ではなくて多くの問題を含んでいる。

  • squashをすべきか
  • push -fを許すべきか。許す場合はどのようなブランチや状況に対して許すべきか
  • 歴史改変をどこまで許すべきか。特にコードレビューへの対応記録など。また、改変後の粒度はどうあるべきか
  • マージの反映はgithubなど中央リポジトリの機能で行うのか自力で行うのか

merge派の極みは、一切のrebaseをせずmergeのみで競合を解決するというもの。rebase派の極みは、ブランチでのすべての変更をsquashしてマージ直前のコミットからrebaseするというもの(すべてが下記のようなコミットツリーになる)

*   Merge branch 'branch3' into 'develop' @user1
|\
| * Fix zzz
|/  
*   Merge branch 'branch2' into 'develop' @user1
|\
| * Fix yyy
|/  
*   Merge branch 'branch1' into 'develop' @user1
|\
| * Fix xxx
|/  
*

 

前者はコミットツリーが汚くなりすぎて何がなんだかわからなくなりがち。後者はあらゆる履歴が1つにまとめられるので経緯情報が失われる。

結局のところ、起こったことはすべてそのまま記録すべき(経緯が大事)派と、なにをもとになにを修正したかを明快にすべき(結果が大事)派の争いであり、どちらも正しい。だからタチが悪い。

 

大抵はrebase派のほうがGitに詳しくてmerge派はrebase派の言っていることが理解できてないことも多い。しかし、rebase派は当然のようにpush -fの使用を強制するためmerge派からすると「ただでさえ難しいGitのさらによくわからない手順を覚えた上で禁忌とされる『他人のコミットを壊す』恐怖に怯えなければならない」ため受け入れ難い。

これでさらに、rebase派が煽り気味にマウントとったりすることもまれによくあるのでろくなことにならない。そして根本的にどちらの言ってることも正しいので全然落とし所がみつからない。嗚呼なぜこんな苦労をせねばならんのか。

 

分散リポジトリなんて誰もつかってねーじゃねーか問題

gitは分散リポジトリなので、中央集権サーバーを持たずにお互いpull pushをして同期し合うモデルが可能だったはずだ。

こういう運用をしてたことがあったのかは知らないが、2022年現在、ほぼ全ての人がサーバークライアントで使ってるだろう。githubみたいな「originたるサーバー」と、自分だけのローカル。

 

結局GitじゃなくてGithubの機能じゃねーか問題

Git管理で最も役に立つ機能はプルリクエストだろう。安心安全なシステム開発にあたって変更をコントロールしレビューの強制を実現できる仕組みは素晴らしい。ほとんどの人はプルリクレビューのためにGitを使っているのではないかとすら思う。

先に示した運用ルールに則したマージ戦略の徹底やPRを介さない直接pushの禁止、歴史改変の禁止などをブランチ単位でコントロールできる機能は、開発現場の秩序維持にとても役に立つ。

 

素晴らしい。しかしこれらは全部GitHubの機能じゃねえか!GitHubなかったら分散という名のただのややこしくて理解しづらい仕組みじゃねえか!

 

ブランチのメンタルモデルからの乖離

Gitをよく知ってる人ならご存知なように、ブランチは「枝」という名前ではあるが、実際には全然枝じゃ無い。コミットである。

ほとんどの人がメンタルモデルとして枝分かれの樹形図をイメージするが、実際はコミットをたどることによって「結果的に」ツリーが構築されてるにすぎない。

樹形図表示ツールの決定版が出てこないのも、樹形図を分岐や結合に絞ってうまく意図とあうように表示しにくいのも、根本的にはこれが影響している。このモデルはGitの核であるため一生解決しないことがほぼ確定である。つらい。

 

コミットIDがハッシュ

いやわかるよ。Gitにとってハッシュこそが肝なのはさ。

でもあえて言わせてもらおう、ブランチ名+連番とかでコミットが一意に表せてほしい。rev123まで戻して再デプロイして!とか言いたいのだ。df87aj2まで戻して!とかなんやねん伝えにくいわ

 

まとめ/結局なにがしたいのか

原点に立ち返って考えてみよう。

多くの人にとってGitは手段である。安全安心なソフトウェアを作ることが目的で、そのために変更管理が必要だ。変更管理(とそれにまつわるレビューや承認や修正の管理)をしやすくしたいのである。

その目的に対して、Gitは難しすぎる。メンタルモデルと実体は合わないし、メンタルモデルを正確に反映するGUIツールはないし、どちらも正しいが相反する2つのマージ戦略がある。

われわれは、Gitについて詳しくなりたいわけではない。さいきょうのGitFlowを作りたいわけでもない。Gitが開発者の嗜みの一つとして当然のように存在することでシステム開発の間口が狭くなることを憂慮している。

どうしてたかがソース管理のためにこんな難しいものを理解しなければならないのか。欲しい機能はプルリクレビューだけだ。ブランチ作るのが早いsvnがあればそれでも全然いい。

Gitは神が戯れにつくったツールで、人類に広く普及するには早すぎる。

*1:厳密にはローカルリポジトリとワーキングツリーは別物だが素人視点の話なのでそんなところに突っ込むなかれ

*2:〇〇は私が更新するまでだれもコミットしないで、と宣言するとか