← 解説「git add の正体 — ステージは「次のtreeの下書き」」に戻る
サンプルコードで身につける: git add の正体 — ステージは「次のtreeの下書き」
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
11つのファイルが3つの姿を持つ
addしたあとにさらに編集すると、作業ツリー・ステージ・最新コミットで中身が食い違います。git status がこれを2行に分けて表示する理由が、実際の出力で分かります。
$ printf 'version 2\n' > memo.txt
$ git add memo.txt # ← ここでステージに version 2 が載る
$ printf 'version 3\n' > memo.txt # ← さらに編集
$ git status
Changes to be committed:
modified: memo.txt ← ステージにある version 2
Changes not staged for commit:
modified: memo.txt ← 作業ツリーの version 3
# 同じファイルが2箇所に出るのは、姿が2つあるから
# この状態でcommitすると、記録されるのは version 2
2どの版がコミットされるかを確かめる
git diff は「作業ツリーとステージ」の差、git diff --staged は「ステージと最新コミット」の差を見ます。この2つを使い分けると、今コミットしたら何が入るかを事前に確認できます。
# ステージと作業ツリーの差(= まだコミットに入らない分)
$ git diff
-version 2
+version 3
# 最新コミットとステージの差(= 今コミットしたら入る分)
$ git diff --staged
-version 1
+version 2
# 最新の編集も入れたいなら、もう一度 add する
$ git add memo.txt
$ git diff # 差が無くなった
$ git diff --staged
-version 1
+version 3
3addの時点でblobはもうDBに入っている
コミットを待たずに、addした瞬間オブジェクトが作られます。commitしていないのにcat-fileで中身が取り出せることを確認すると、addとcommitの分担がはっきりします。
$ printf 'まだコミットしていない内容\n' > draft.txt
$ git add draft.txt
# ステージの中身を見る(パス → blobハッシュ の一覧)
$ git ls-files --stage draft.txt
100644 9f8e7d6c5b4a39281706f5e4d3c2b1a098765432 0 draft.txt
# コミットしていないのに、もうオブジェクトDBから取り出せる
$ git cat-file -p 9f8e7d6c5b4a39281706f5e4d3c2b1a098765432
まだコミットしていない内容
# → add = blobを作ってDBへ入れ、ステージの一覧に載せる
# commit = ステージの一覧から tree を組んで commit で包む
4ステージから tree が組まれる過程
commitがしていることは「ステージの一覧を階層に組み直してtreeを作る」ことです。パスの一覧からディレクトリ構造が復元される様子を追うと、なぜサブディレクトリの分だけtreeが増えるのか分かります。
Python
5「addを忘れてcommitした」が起きる理由
commitはステージだけを見て、作業ツリーを一切見ません。だからaddし忘れると、編集したはずの内容が入りません。よくある失敗を再現し、原因が仕様通りの動作だと理解します。
Python