動かして理解するGit | addとcommit編
この記事では、Gitのadd
, commit
コマンドについて深掘りした内容をまとめます。
addコマンド
addは選択したファイルだけをコミットするための仕組みです。
具体的には、以下のことをしています。
- ファイルの内容を圧縮してBlobオブジェクトを作成し
.git/objects/
に保存。 - ステージングエリア(
.git/index
)に登録。
addの内部的な動作を追ってみる
下準備
以下のようにファイル・フォルダを配置し、a.txtに変更を加えました。
/folder1
├── /folder-1-1
| └── c.txt
└── b.txt
a.txt // ← ここを変更・addしてみる。
Tree・Blobオブジェクトの確認用。
ここは`a.txt`です。
+
+ ここを変更して、addの挙動を見てみる。
以下のコマンドでindexに登録されたファイルと、そのBlobオブジェクトのハッシュを見ることができます。
git ls-files --stage
addしていないときのindex
まずは、addしていない状態でindexを見てみます。
PS C:\Users\...\git-playground> git ls-files --stage
100644 d8038ab201a19d961c0be971a06479e1b857490a 0 a.txt
100644 6b2641653428bc52ebadf30821061fe6b148b039 0 folder1/b.txt
100644 b993a127140d50bab9c349674730d160a264f29a 0 folder1/folder1-1/c.txt
cat-file
コマンドでa.txtの中身を見てみると、変更前の内容であることが分かります。
PS C:\Users\...\git-playground> git cat-file -p d8038ab201a19d961c0be971a06479e1b857490a
Tree・Blobオブジェクトの確認用。
ここは`a.txt`です。
addした後のindex
今度は、git add a.txt
をした後のindexを見てみます。
PS C:\Users\...\git-playground> git ls-files --stage
- 100644 d8038ab201a19d961c0be971a06479e1b857490a 0 a.txt
+ 100644 8b36dadad0a62065b636af374e9c8d4c923924cb 0 a.txt
100644 6b2641653428bc52ebadf30821061fe6b148b039 0 folder1/b.txt
100644 b993a127140d50bab9c349674730d160a264f29a 0 folder1/folder1-1/c.txt
a.txtのハッシュが先ほどと変わっているのが分かります。
中身を見てみると、変更後の内容になっています。
PS C:\Users\...\git-playground> git cat-file -p 8b36dadad0a62065b636af374e9c8d4c923924cb
Tree・Blobオブジェクトの確認用。
ここは`a.txt`です。
ここを変更して、addの挙動を見てみる。
add をすると、選択したファイルの新しいBlobオブジェクトが作成され、indexに上書きされることが分かりました。
add しても、変更前のBlobオブジェクトは削除されずに.git/objects/
にあり、過去のコミットから参照されます。
commitコマンド
コミットでは新しい変更履歴を作成します。
具体的には、以下のことをしています。
- indexを読み取り新しくTreeオブジェクトを作成する。
- スナップショットを作成・登録する。
- Commitオブジェクトを作る。
- HEADを新しいコミットを指すように進める。
コミットの内部的な動作を追ってみる
addコマンドのときに、ステージングした変更があるので、それをコミットしてみます。
下準備
現在はwrite-articleブランチにいるので、.git/HEADの中身は以下のようになっています。
ref: refs/heads/write-article
コミット前
write-articleブランチは最新のコミットを指しています。
c175cc4b295c544d3b80662f46cf06383171a191
コミット後
以下のようにコミットしてみました。
PS C:\Users\...\git-playground> git commit -m "コミットして動作確認"
[write-article fda604c] コミットして動作確認
1 file changed, 3 insertions(+), 1 deletion(-)
コミット前後の.gitディレクトリを比較してみると、
何やら新しく2つのオブジェクトが作成されていました。
片方はCommitオブジェクト。
PS C:\Users\...\git-playground> git cat-file -p fda604c66974a2eb6352141305481eb268700996
tree fcfd7cb8d9db0f93c35aae39692800d13eb320af
parent c175cc4b295c544d3b80662f46cf06383171a191
author makim0939 <makim0939@gmail.com> 1757245797 +0900
committer makim0939 <makim0939@gmail.com> 1757245797 +0900
コミットして動作確認
もう片方はTreeオブジェクトです。
PS C:\Users\...\git-playground> git cat-file -p fcfd7cb8d9db0f93c35aae39692800d13eb320af
100644 blob 8b36dadad0a62065b636af374e9c8d4c923924cb a.txt
040000 tree d8b465f99cbd8047e700b7a5843dccaf685efb77 folder1
write-articleブランチが新しいコミットを指すように変更されていました。
fda604c66974a2eb6352141305481eb268700996
.git/logsの現在のブランチに、新しいコミットが記録されていました。
中身は見れないですが、.git/indexも書き換わっていました。
- コミットすると、新しくTreeオブジェクトが作成され、この時点でのスナップショットが記録される。
- そのスナップショット(ルートディレクトリのTreeオブジェクト)をもつCommitオブジェクトが新しく作成される。
- HEADが指すブランチ(現在のブランチ)が指す先が今回のコミットに変更される。
- logsにコミットの情報が追加される。
- indexでおそらくステージングの情報が更新される。
Discussion