Gitレポジトリはパッチの集積ではなくてスナップショットの集積である。

Gitはパッチを保存してはいない

勘違いしてる人が非常に多いのですが、Gitレポジトリに保存されているのはパッチ(差分)ではなくスナップショットです。

例えば、1から1億までの数字が書かれたテキストファイルを作ったとしましょう。
1
2
3
[中略]
100000000
このファイルをコミットすると、Gitレポジトリには巨大なファイルが1つ追加されます。
(※実際にはコミットオブジェクトやツリーオブジェクトといったファイルも別途追加されますが、細かいことは省きます)

ここまでは誰でも理解できるでしょう。

巨大なファイルに「追記」するとどうなるか

では次に、このファイルの末尾に1行追記します。
100000000
100000001  ← 追記
でこのファイルをコミットします。
するとどうなると思いますか?

Gitレポジトリに巨大なファイルが2つできます。

この後 git show -pしたり git log -1 -p したりすると差分が表示されますが、
あなたが見ているその差分は、上記2つの巨大なファイルを比較して導き出された導出物にすぎないのです。

コミットする = スナップショットを保存する

したがって、コミットするという行為は、Gitの内部構造的には「変更を記録する」ではなく「変更後のスナップショットを保存する」ということになります。
また、pushとfetchは、「変更を送る/取得する」ではなく「スナップショットを送る/取得する」ということになります。

スナップショットを意識できるようになるとGitは上達する

この「スナップショット」という概念を意識しているかどうかが、Git初心者と上級者の大きな違いであると言えると思います。
スナップショットの実体は .git/objects/ です。
スナップショットを詳しく見るためのコマンドとしてgit ls-treeやgit cat-fileなどがあります。
一度これらのコマンドでスナップショットを自分の目で見てみると理解が深まることでしょう。

詳しい解説は省きますが、下記のような感じで使えます。
$ git cat-file -p HEAD
tree b30a08c46c6e92c6ff76494c1c366acb7064a4a4  ← これがスナップショット
parent 93868ccce45efa89df964f16b3d768e85bd82ceb
author DQNEO <dqneoo@***.com> 1379323710 +0000
committer DQNEO <dqneoo@***.com> 1379323710 +0000

append 1
$ git cat-file -p b30a08c46c6e92c6ff76494c1c366acb7064a4a4
100644 blob 4a529b7234e3b1659601e067082e9db149c5c839    numbers.txt
100644 blob d00491fd7e5bb6fa28c517a0bb32b8b506539d4d    plus1.txt

Enjoy Git!
カテゴリ: