mtbの学んだことのブログ

とあるPythonエンジニアのブログ

Gitが大切にしていること、成り立ち、他との違い

僕は、やっぱりツールを使っていて、「中身がブラックボックスなのは、気持ちが悪いなあ。」と思ってしまうたちのようです。

だって、よくわかんないんだもの。気持ち悪い。

という訳で、Gitについて、もっと詳しくなりたいと思いました。

ProGitを読んでいます。ここでは、個人的な発見を記します。

Pro Git 日本語版電子書籍公開サイト

CVCSの問題とDVCSの成り立ち

個人的には、以下の3点が重要でした。

  • CVCS(集中バージョン管理システム)は、中央サーバーが単一障害点になるのがよくなかった
  • 中央サーバーを作らなきゃいんだ。ということでDVCS (分散バージョン管理システム)が誕生した。
  • CVCSで出来なくて、DVCSで出来るワークフローがあるが、それらは、各DVCSの階層モデルによる副次的な産物だった。

この辺りに書いてます。

Git - バージョン管理に関して

Gitで大切にされていること

個人的には、以下の5点を目標に開発されているとの話が、重要だと思いました。

  • スピード
  • シンプルな設計
  • ノンリニア開発(数千の並列ブランチ)への強力なサポート
  • 完全な分散
  • Linux カーネルのような大規模プロジェクトを(スピードとデータサイズで)効率的に取り扱い可能

以下に書いてます。

Git - Git略史

これを見て、他のDVCSやCVCSは、以下のような特徴を持っていたことがわかります。

  • Gitに比べて、スピードが遅かった
  • Gitに比べて、設計がシンプルではなかった
  • Gitに比べて、ノンリニア開発へのサポートが貧弱
  • Gitに比べて、完全に分散しているといえなかった
  • Gitに比べて、プロジェクトが大規模になると効率的に取り扱えなかった

そして、Gitの5つの目標を達成するために、Gitの各コマンドが作られていると思うので、その気持ちで読み進めていきます。(僕はプロダクトのコンセプトを知ることが、プロダクトの一つ一つの機能を理解するためのいちばんの近道だと思ってます。)

他のCVCSとGit

以下のページにある「GitはSubversionと情報の格納の仕方が違う」という情報は、僕にとって、すごく重要でした。

Git - Gitの基本

なぜなら、僕は、Subversionを利用していましたし、Subversionの情報の持ち方を理解していたので、「Gitもきっと同じだろう」と思っていました。それが混乱を加速させていました。

僕にとって、衝撃だったのは、Gitはスナップショットを保持していて、差分を保持していない。ということでした。

それによって僕が、Gitを利用していて違和感を感じていた以下のような疑問が解消されました。

git cloneが遅い?

疑問その1:なぜ、これくらいのテキストファイルしか入っていないGitリポジトリをローカルにコピーしてくるだけなのに、こんなに時間がかかるのか?裏で何が動いているのか?SVNリポジトリで、もっと大容量のファイルを管理していたことはあったが、チェックアウトはもっと高速だった。当時の環境と比較して現在の環境のネットワークが低速だとは思えない。Mercurialをcloneした時ももっと速いような気がしてる。git cloneでは何が起きているんだろう?

答え1:Gitリポジトリをcloneするということは、これまでの履歴も含めて全ての情報をコピーするということ。しかもGitリポジトリには、履歴がスナップショットで格納されているので、変更回数の増加とリポジトリの肥大化のスピードは、SVNMercurialの比ではない。ただし、それは、開発中のスピードダウンではなく、開発を開始する前に時間がかかるだけである。Gitは開発者がストレスフリーに開発が行えるために作られたバージョン管理システムであって、管理者がリソースを効率的に利用して、新しい環境を作るコストを抑えるために作られたバージョン管理システムではない。ということ。

gitのbranch切り替えが高速すぎる?

疑問その2:Gitでbranchを変更した際に、切り替えが高速すぎて、本当に切り替わっているのか不安になる。例えば、ブランチの切り替えでは、ファイルが切り替わるが、切り替えが実施されているのかどうかもわからないほど高速で切り替わっている。何が起きているのかわからないような感覚になる。これは何が動いているのか?僕が思っているbranch切り替えとgitのbranch切り替えは違うように思えるが、これまでの経験は、全て使えないのか、一部使えないのかどちらだろうか。

答え2:Gitは差分を管理しているわけではなく、スナップショットを管理している。言い換えるなら、「このコミットが行われた時に配置されていたファイルは何か」という情報を管理している。branchが切り替わっても、ただ単にその時に配置されていたファイルの情報と現在配置されているファイルの情報の差分を見て、違うファイルを差し替えるだけである。だから、その間にたくさんのコミットがあったとしても、関係がないし、切り替えが高速になる。これまでの経験が、全て使えないとは言えないが、仕組みが違うということは頭に入れておいた方が良さそう。

gitのrebaseでなぜマージ処理が走る?

疑問3:gitでは、rebaseした際にコミットが実行されているように見える。rebaseの際は、マージもされているように見えるが、何か違和感がある。rebaseが自分のイメージしている動きと何か違う気がする。処理速度が、自分の思っているスピードと違う。これまでに使っていたSVNと同じように使っていると何か地雷を踏みそうな予感がする。マージしているつもりが、マージされていない。などの問題がどこかで起きていないのか不安だ。後ろで何が行われているんだろう?自分が何を勘違いしているのだろうか。

答え3:gitは、rebaseが行われた際、指定されたポイントから、現在のブランチに行われたコミットを一つ一つ確認しながら、ファイル状態をマージしていく。gitは、差分を持っているわけではなく、スナップショットで管理しているので、rebaseが実施されたタイミングで、同じファイルが更新されれば、それらのスナップショットを元に、一つ一つのファイルと差分を取り、マージ作業を行なっていく。rebaseのタイミングでファイルがマージが行われるということは注意した方が良い。

Gitのコミットの完全性

僕にとって、こある意味で衝撃的だった話は以下です。

  • Gitのほとんどすべてのコマンドが、データを追加するだけ。
  • Gitでは、UNDOを実行したり、データを消去することは困難である。

ただ、これは次のように紹介されていたのも印象的です。

激しく物事をもみくちゃにする危険なしに試行錯誤を行なえるため、これはGitの利用を喜びに変えます。

引用元: Git - Gitの基本

どのあたりが、危険なしに試行錯誤を行えるんだろう・・・というのはよくわかっていない。今のところ、gitはすぐにぐちゃぐちゃになるなあ。と思っている。

時間が来たので、一旦ここで。続きは、そのうち読む。