1. 視覚から理解するGit
こんにちは、最近入社したymizushiです。
Gitはバージョン管理システムのデファクトスタンダードになったと言っていいと思いますが、
Subversionとは内部構造が違うのに、コマンドラインからは中途半端に似たようなインターフェースになっているため、
Gitを使っているけど実はよくわかっていないという方も多いと思います。
でもGitの基本的な構造自体は驚くほどシンプルで、
普通に使うだけなら下の図を見て理解するだけで大丈夫だと思います。
(クリックで拡大します)
この図はGitの基本構成を本家GitのDocumentationを参考に、
自分なりにわかりやすく図にしてみたものです。
これから実際のコマンドラインを通して、
どのコマンドがどのような意味を持ち、
図ではどのような部分にあたるのかを説明していきます。
2. コマンドから理解するGit
これからの説明は、branchに新たに
piyo.clj
foo.clj
bar.clj
というファイルを作成したという前提で進めていきます。
work treeのrootで以下のコマンドを実行します。
1
2
3
4
5
6
7
8
9
|
$ git status
# On branch master
# Untracked files:
# (use “git add …” to include in what will be committed)
#
# bar.clj
# foo.clj
# piyo.clj
# nothing added to commit but untracked files present (use “git add” to track)
|
この3ファイルが図の「untracked」にあたります。
今度は以下のコマンドをを実行します
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$ git add piyo.clj
$ git status
# On branch master
# Changes to be committed:
# (use “git reset HEAD …” to unstage)
#
# new file: piyo.clj
#
# Untracked files:
# (use “git add …” to include in what will be committed)
#
# bar.clj
# foo.clj
|
この操作によりpiyo.cljのgit addした時点での全ての差分が、
「staged」に取り込まれます。
この状態でpiyo.cljを編集し、git statusを実行すると
以下のような出力がされます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
$ echo “;piyo” >> piyo.clj # piyo.cljを編集
$ git status
# On branch master
# Changes to be committed:
# (use “git reset HEAD …” to unstage)
#
# new file: piyo.clj
#
# Changes not staged for commit:
# (use “git add …” to update what will be committed)
# (use “git checkout — …” to discard changes in working directory)
#
# modified: piyo.clj
#
# Untracked files:
# (use “git add …” to include in what will be committed)
#
# bar.clj
# foo.clj
|
前回の出力と違う部分は
1
|
# Changes not staged for commit:
|
の部分です。
つまり「not staged」が追加されたようです。
同じファイルなのになぜnew file とmodifiedに分かれたのかと疑問に思った人がいるかもしれませんが、
add して「staged」の状態に変更してから、さらに変更が加えられると、
add してからの差分が「not staged」となります。
つまり、
ブランチから行った変更 = 「stagedの差分」+「not staged」の差分 + 「untracked」
です。
またcommitでは「staged」に反映された変更しかリポジトリに反映出来ないため、
commitされる内容と git diff –cachedで表示される内容は等価です。
3. スナップショットと差分
work treeはbranchからの差分で表現されますが、
gitに取り込まれるのはスナップショット(ファイルのデータそのもの)です。
「staged」での差分をあてた内容がデータとしてblobオブジェクトで作成され、
blobへの参照を持ったtreeと
treeへの参照と親commit(基本的にそのbranchの一つ前のcommit。mergeの際は二つ以上の親を持つ)への参照
を持ったcommitオブジェクトが生成されます。
Gitではcommitごとにこのようなことが行われますが、
commitが持っているtree構造は基本的に普通のファイルシステムとそう変わりがなく、
違うのはblobは不変であるということです。
以上のことさえわかっていれば、
例えば、git reset でどのような情報が失われるのか、
なども自ずとわかってくると思います。