📌 定義
残念なことに表記が結構ぶれていて、いくつもの言い方があって混乱しやすくなっているのが現状です.本書では次のようにします.
🔹 snapshot (スナップショット)
バージョンごとのファイルそのもの.
🔹 worktree (作業ツリー)
ローカルにあるファイルを編集する場所です.リモートには存在しません.作業ツリーがないリポジトリのことを bare
リポジトリといいます.
🔹 index (インデックス)
次のコミットのスナップショットです.ステージングエリアとも言われます.作業ツリーからインデックスにスナップショットを記録することを staging(ステージング) といいます.そのため、staged とも言われます.他には cached とも言います.Gitのコマンドでは、stage(d)
, cached
を指定することがあるので覚えておく必要があります.
🔹 database (データベース)
Gitオブジェクト(後述)のデータベースです.ローカルリポジトリとも言われる部分ですが、ローカルリポジトリはコミット履歴や設定ファイルなどさまざまな情報が含まれているものです.
📌 ファイルの状態
Git から見た作業ツリーのファイルは次の3種類に分けられます.
- バージョン管理されていないファイル (Untracked)
- バージョン管理されていて、更新されていないファイル (Unmodified)
- バージョン管理されていて、更新されたファイル (Modified)
バージョン管理されていないファイルを管理対象とするには、まずステージングしてコミットします.
Untracked -> Staged -> Unmodified
バージョン管理されているファイル(Unmodified)を編集して更新すると(Modified)になって、ステージングできます.
Unmodified -> Modified
ステージングすると更新されたファイルのスナップショットがインデックスに登録されます.
Modified -> Staged
これらの関係は次の図をご覧ください.
▲図: ファイルの状態 (「Pro Git 2nd edition 日本語版」p.25)
📌 Gitリポジトリ
git init
コマンドでGitリポジトリを作成できます.
PS > git init
Initialized empty Git repository in F:/re-git/.git/
Gitリポジトリの中は次のようになっています.
PS > lat
.
└── .git
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── prepare-commit-msg.sample
│ ├── push-to-checkout.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
├── refs
│ ├── heads
│ └── tags
├── config
├── description
└── HEAD
🔹 hooks/
フックスクリプトを格納するディレクトリです.ここでは詳しく解説しません.
🔹 info/exclude
バージョン対象外にしたいファイルを指定できます.これは .gitignore
でも同様のことができますが、ローカル環境でのみ適用したい場合に使います.
PS > cat .git\info\exclude
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
🔹 objects/
Gitオブジェクトを格納するディレクトリです.Gitオブジェクトについては後述します.
🔹 refs/
参照情報を格納するディレクトリです.参照とは、コミットを指すポインタのことです.実体はコミットのハッシュ値が記録されたファイルです. refs/heads/
ディレクトリには各ブランチの最新のコミット情報が格納されています.
🔹 config
ローカルの設定ファイルです.
PS > cat .git\config
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
filemode
filemode
はパーミッションの設定です.true だと環境によってパーミッションが変化する場合があります.デフォルトは false です.
bare
bare
はベアリポジトリかどうかです.false なら作業ツリーを認識します.
symlinks
symlinks
はシンボリックリンクを有効にするかどうかです. デフォルトは false です.
repositoryformatversion
repositoryformatversion
はリポジトリのフォーマットバージョンです.extensions.*
キーを指定する場合は 1 を、そうでないなら 0 を指定します.
ignorecase
ignorecase
はファイル名の大文字小文字を区別しないかどうかです.
logallrefupdates
logallrefupdates
はreflogを取るかどうかです.ベアリポジトリでは false
、そうでないなら true
になります.
🔹 description
Gitリポジトリの説明が格納されています.
PS > git cat .git\description
Unnamed repository; edit this file 'description' to name the repository.
🔹 HEAD
現在のHEAD情報です.HEADは通常ブランチを指します.
PS > cat .git\HEAD
ref: refs/heads/main
Gitリポジトリ初期化時では refs/heads/main
が存在しないので、この HEAD は無効になっています.また、ブランチではなくコミットを直接指すこともあります.この場合、 detached HEAD
となります.
📌 ファイルの状態を確認
git status
で確認できます.確認できるのは作業ツリーとインデックスでの状態です.
PS > git status
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
📌 ファイルの追加
バージョン管理したいファイルを追加してみましょう.まずファイル(README.md)を作成します.
PS > echo 'My Project' > README.md
PS > git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)
ファイル状態を確認するとREADME.mdファイルはUntrackedであることがわかります.バージョン管理するには、まずステージングします.これは git add
を使います.
PS > git add README.md
warning: in the working copy of 'README.md', CRLF will be replaced by LF the next time Git touches it
PS > git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
出力にもある通り、ここで git rm --cached
を使うとインデックスから取り除くことができます.
PS > git rm --cached README.md
このとき、作業ツリーにあるファイルは削除されません.もし、作業ツリーにあるファイルも無かったことにしたい場合、 -f
を指定します.
PS > git rm -f README.md
ファイルを追加した状態でGitリポジトリの中身はどうなっているか確認します.
PS > lat
.
├── .git
│ ├── info
│ │ └── exclude
│ ├── objects
│ │ ├── 56
│ │ │ └── 266d360f3da9f922766101055bd78ffa3724bf
│ │ ├── info
│ │ └── pack
│ ├── refs
│ │ ├── heads
│ │ └── tags
│ ├── config
│ ├── description
│ ├── HEAD
│ └── index
└── README.md
objectsディレクトリにファイルが追加され、indexファイルが作成されています.これらが一体何なのか理解するためにGitオブジェクトについて知る必要があります.
📌 Gitオブジェクト
GitオブジェクトはGitがバージョン管理するために作成するオブジェクトのことです.これらは .git\objects
ディレクトリに作成されます.本書ではこのディレクトリのことをデータベースと呼ぶことにします.
Gitオブジェクトは以下の4種類あります.
- blobオブジェクト
- treeオブジェクト
- commitオブジェクト
- tagオブジェクト
Gitオブジェクトはバイナリ形式で、名前がハッシュ値(SHA-1)になっています.データベースにはハッシュ値の先頭2文字のディレクトリの中に、その文字分除外したファイル名で格納されています.ですから、 56/266d360f3da9f922766101055bd78ffa3724bf
というのは 56266d360f3da9f922766101055bd78ffa3724bf
というハッシュ値になります.
Gitオブジェクトはその種類とその情報が圧縮されて保存されています.これらを中身を見るためのコマンド(git cat-file
)が用意されています.
-t
を指定すると種類、 -p
を指定すると情報、 -s
を指定すると圧縮前のサイズがわかります.
PS > git cat-file -t 56266d360f3da9f922766101055bd78ffa3724bf
blob
PS > git cat-file -p 56266d360f3da9f922766101055bd78ffa3724bf
My Project
PS > git cat-file -s 56266d360f3da9f922766101055bd78ffa3724bf
11
README.mdファイルを追加したことで、blobオブジェクトが生成されたことがわかります.
🔹 indexファイル
indexは次のコミットのスナップショットであると前述しました.その実体がこのファイルになります.indexファイルはバイナリで、バージョン管理しているすべてのスナップショットを記録しています.
PS > hexyl .git\index
これは次のように出力されます.
このファイルに記録されている情報を確認するコマンドがあります.それは git ls-files --stage
です.
PS > git ls-files --stage
100644 56266d360f3da9f922766101055bd78ffa3724bf 0 README.md
これは次のような形式になっています.
<mode> <object> <stage> <file>
🔹 mode
100644
は 0b1000000110100100
のことで、3つのパーツ(10000-000-110100100
)に分けられます.
1000
の部分は、ファイルの種類です.次の種類があります.
-
1000
: regular file -
1010
: symbolic link -
1110
: gitlink
次の000
は使用されていません.最後の 110100100
はUNIXパーミッションです.通常ファイルでは 0755
と 0644
のみです.シンボリックリンクとgitリンクは 0
です.
🔹 object
Gitオブジェクトのハッシュ値です.
🔹 stage
ステージ番号はマージ衝突時に使われます.
- Slot 0: “normal”, unconflicted , all-is-well entry.
- Slot 1: “base”, the common ancestor version.
- Slot 2: “ours”, the target (HEAD) version.
- Slot 3: “theirs”, the being-merged-in version.
🔹 file
ファイル名です.
📌 コミット
インデックスに更新されたスナップショットが記録されていればコミットできます.コミットしてみましょう.
PS > git commit
上記のコマンドを実行するとコミットメッセージ(.git\COMMIT_EDITMSG
ファイル)がエディタで開かれます.メッセージを書いて保存し、閉じるとコミットが実行されます.もし、コマンドと一緒にメッセージを書きたい場合、 -m
を指定します.
PS > git commit -m "first commit"
[main (root-commit) b4c9631] first commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
この時点のGitリポジトリがどうなっているか確認してみます.
PS > lat
.
├── .git
│ ├── info
│ │ └── exclude
│ ├── logs
│ │ ├── refs
│ │ │ └── heads
│ │ │ └── main
│ │ └── HEAD
│ ├── objects
│ │ ├── 56
│ │ │ └── 266d360f3da9f922766101055bd78ffa3724bf
│ │ ├── b4
│ │ │ └── c96315ae08b029192fa57b46b035d0317018cc
│ │ ├── c8
│ │ │ └── a887332c98b8d43304c2d8c4ba0389f2665d60
│ │ ├── info
│ │ └── pack
│ ├── refs
│ │ ├── heads
│ │ │ └── main
│ │ └── tags
│ ├── COMMIT_EDITMSG
│ ├── config
│ ├── description
│ ├── HEAD
│ └── index
└── README.md
いくつか追加されていますね.更新されたファイルをわかりやすく見てみましょう.
PS > laft
これは次のような出力になります.
タイムスタンプを見ると以下のファイルがコミット時に生成または更新されたことがわかります.
.git\logs\refs\heads\main
.git\logs\HEAD
.git\refs\heads\main
.git\objects\b4\c96315ae08b029192fa57b46b035d0317018cc
.git\COMMIT_EDITMSG
.git\index
.git\objects\c8\a887332c98b8d43304c2d8c4ba0389f2665d60
それぞれ見ていきましょう.
🔹 logs/
コミットの変更が記録されます.それぞれのファイルは次のようになっています.
PS > cat .git\logs\refs\heads\main
0000000000000000000000000000000000000000 b4c96315ae08b029192fa57b46b035d0317018cc mebiusbox <mebiusbox@gmail.com> 1676196569 +0900 commit (initial): first commit
PS > cat .git\logs\HEAD
0000000000000000000000000000000000000000 b4c96315ae08b029192fa57b46b035d0317018cc mebiusbox <mebiusbox@gmail.com> 1676196569 +0900 commit (initial): first commit
これは 0000000000000000000000000000000000000000
から b4c96315ae08b029192fa57b46b035d0317018cc
のコミットに変わったことを表しています.この履歴は git reflog
で確認できます.
PS > git reflog
b4c9631 HEAD@{0}: commit (initial): first commit
🔹 refs/heads/main
これはmainブランチの最新のコミットを指す参照です.内容は次のようになっています.
PS > cat .git\refs\heads\main
b4c96315ae08b029192fa57b46b035d0317018cc
つまり、 b4c96315ae08b029192fa57b46b035d0317018cc
はコミットを表すオブジェクトであることが想像できると思います.
🔹 commitオブジェクト
このcommitオブジェクトを見てましょう.
PS > git cat-file -t b4c96315ae08b029192fa57b46b035d0317018cc
commit
PS > git cat-file -p b4c96315ae08b029192fa57b46b035d0317018cc
tree c8a887332c98b8d43304c2d8c4ba0389f2665d60
author mebiusbox <mebiusbox@gmail.com> 1676196569 +0900
committer mebiusbox <mebiusbox@gmail.com> 1676196569 +0900
first commit
PS > git cat-file -s b4c96315ae08b029192fa57b46b035d0317018cc
175
commitオブジェクトの中は、 tree
, author
, committer
があります.この tree
オブジェクトを見てみましょう.
📌 treeオブジェクト
先ほどのcommitオブジェクトが指していたtreeオブジェクトを見てみましょう.
PS > git cat-file -t c8a887332c98b8d43304c2d8c4ba0389f2665d60
tree
PS > git cat-file -p c8a887332c98b8d43304c2d8c4ba0389f2665d60
100644 blob 56266d360f3da9f922766101055bd78ffa3724bf README.md
PS > git cat-file -s c8a887332c98b8d43304c2d8c4ba0389f2665d60
37
treeオブジェクトの中身はインデックスに書かれたものに似ていますね.treeオブジェクトはディレクトリを表すので、ツリー構造になっています.今回はルートディレクトリにあるファイルだけですが、サブディレクトリがあれば、treeオブジェクトの中で別のtreeオブジェクトを参照します.
📌 Gitオブジェクトと参照
これまで見てきたように、HEAD はブランチを指し、ブランチはcommitオブジェクトを参照し、commitオブジェクトはtreeオブジェクトを参照し、treeオブジェクトはblobオブジェクトやTreeオブジェクトを参照します.
HEAD -> Branch -> commit -> tree -> blob, tree
今回は最初のコミットでしたが、通常はcommitオブジェクトに親のコミット情報(parent
)が含まれています.
これらの関係から HEAD やブランチ、タグは唯一のコミットを特定できるので、Gitコマンドでコミットを指定する部分に使うことができます.Gitコマンドのパラメータで commit-ish
と指定されている部分は、コミットが特定できるものなら指定できることになります.そして、参照しているコミットを調べるコマンド(git rev-parse
)があります.
PS > git rev-parse main
b4c96315ae08b029192fa57b46b035d0317018cc
PS > git rev-parse HEAD
b4c96315ae08b029192fa57b46b035d0317018cc
📌 初回コミットの取り消し
最初のコミットを取り消すにはどうすればよいでしょうか.それには、 git update-ref
コマンドを使います.これは参照を安全に書き換えることができるコマンドです.-d
オプションを指定して、HEADを無効な値 (0000000000000000000000000000000000000000
= 0)にすることで、初回のコミットを取り消すことができます.コミットのログで、40文字分の0が並んだ値は、無効な値だったんですね.
PS > git update-ref -d HEAD
.git/logs/HEAD
はHEADを操作するとその記録が残ります.もう一度見てみましょう.
PS > cat .git/logs/HEAD
0000000000000000000000000000000000000000 b4c96315ae08b029192fa57b46b035d0317018cc mebiusbox <mebiusbox@gmail.com> 1676196569 +0900 commit (initial): first commit
b4c96315ae08b029192fa57b46b035d0317018cc 0000000000000000000000000000000000000000 mebiusbox <mebiusbox@gmail.com> 1676294876 +0900
無効な値に戻っていることが確認できます.しかし、この状態では reflog
では参照できません.
PS > git reflog
何も表示されません.なぜでしょうか.ここからは不正確な情報なので注意です.まず、git reflog
は以下のコマンドのエイリアスです.
git log -g --abbrev-commit --pretty=oneline
-g (--walk-reflogs)
オプションに注目です.ドキュメントには次のように書かれています.
Instead of walking the commit ancestry chain, walk reflog entries from the most recent one to older ones.
要約すると、コミット履歴を辿るのではなく、reflogを辿ると書いてあります.まあ、その通りです.このコマンドで表示されるのは現在のブランチのreflogです.現在のブランチ(main)のreflogは .git/logs/refs/heads/main
です.しかし、コミットがない状態だとこのファイルは存在しません.では、初回コミットして、git update-ref
コマンドを使って取り消した後に、さらにその処理を取り消したい場合はどうするのでしょうか.再コミットすればいいという野暮な発言は却下です..git/logs
ディレクトリを見てみると .git/logs/HEAD
は残っています.これを使うことは出来ないでしょうか.
もちろん、できます.この場合、 git log --reflog
を使います.この --reflog
オプションは何でしょうか.ドキュメントには次のように書かれています.
Pretend as if all objects mentioned by reflogs are listed on the command line as <commit>.
これも要約すると、reflogに記録されているすべてのGitオブジェクトをコミットとして表示するそうです.試してみましょう.
PS > git log --reflog
commit b4c96315ae08b029192fa57b46b035d0317018cc
Author: mebiusbox <mebiusbox@gmail.com>
Date: Sun Feb 12 19:09:29 2023 +0900
first commit
表示されました. --oneline
を指定すれば1行で表示されます.
PS > git log --reflog --oneline
b4c9631 first commit
データベースには、キャッシュとしてまだ残っています.これを使って復元しましょう.
PS > git reset --hard b4c9631
HEAD is now at b4c9631 first commit
ログを見ると次のようになっています.
PS > git log
commit b4c96315ae08b029192fa57b46b035d0317018cc (HEAD -> main)
Author: mebiusbox <mebiusbox@gmail.com>
Date: Sun Feb 12 19:09:29 2023 +0900
first commit
問題なさそうです.ここで、 reflogを見てみましょう.
PS > git reflog
b4c9631 (HEAD -> main) HEAD@{0}: reset: moving to b4c9631
b4c9631 (HEAD -> main) HEAD@{2}: commit (initial): first commit
resetしたことがきちんと記録されています.コミットも元に戻っているので、 .git/logs/refs/heads/main
も存在します.見てみましょう.
PS > cat .git\logs\refs\heads\main
0000000000000000000000000000000000000000 b4c96315ae08b029192fa57b46b035d0317018cc mebiusbox <mebiusbox@gmail.com> 1676295921 +0900 reset: moving to b4c9631
reflogで表示されているHEAD@{2}
の情報はここにないですね. .git/logs/HEAD
を見てみましょう.
PS > cat .git\logs\HEAD
0000000000000000000000000000000000000000 b4c96315ae08b029192fa57b46b035d0317018cc mebiusbox <mebiusbox@gmail.com> 1676196569 +0900 commit (initial): first commit
b4c96315ae08b029192fa57b46b035d0317018cc 0000000000000000000000000000000000000000 mebiusbox <mebiusbox@gmail.com> 1676294876 +0900
0000000000000000000000000000000000000000 b4c96315ae08b029192fa57b46b035d0317018cc mebiusbox <mebiusbox@gmail.com> 1676295921 +0900 reset: moving to b4c9631
こちらを参照しているようです.このあたりの挙動はどうなっているのかはちょっとわかりません.
📌 ガベージコレクト
せっかく復元したのですが、また初回コミットを取り消しましょう.
PS > git update-ref -d HEAD
コミットはなくなりましたが、作業ツリーとインデックスには残ったままです.
PS > git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
すべて無かったことにしましょう. git reset
コマンドを使います.
PS > git reset --hard
作業ツリーやインデックスからは削除されました.確認してみましょう.
PS > lat
.
└── .git
├── info
│ └── exclude
├── logs
│ ├── refs
│ │ └── heads
│ └── HEAD
├── objects
│ ├── 56
│ │ └── 266d360f3da9f922766101055bd78ffa3724bf
│ ├── b4
│ │ └── c96315ae08b029192fa57b46b035d0317018cc
│ ├── c8
│ │ └── a887332c98b8d43304c2d8c4ba0389f2665d60
│ ├── info
│ └── pack
├── refs
│ ├── heads
│ └── tags
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
└── index
データベースには、Gitオブジェクトが残っています.もし、これがこのまま使われなければ不要ですよね.不要なGitオブジェクトを削除する git prune
コマンドがあります.試しに、 -n
を指定(dry-run)して確認します.
PS > git prune -n
何も表示されません.git prune
コマンドが削除するオブジェクトは到達できないオブジェクトです.作業ツリーやインデックスになくとも、前のところで説明したとおり、 .git/logs/HEAD
から参照しているので、到達できます.では、どうするかというとreflogを削除します.通常は git reflog
コマンドを使って削除します.しかし、今回は初回コミットなので、 .git\logs\HEAD
を直接削除します.
PS > rm .git\logs\HEAD
それでは、もう一度 git prune
コマンドを実行してみましょう.
PS > git prune -n
56266d360f3da9f922766101055bd78ffa3724bf blob
b4c96315ae08b029192fa57b46b035d0317018cc commit
c8a887332c98b8d43304c2d8c4ba0389f2665d60 tree
表示されました.実際に削除してみましょう. -v
を指定すれば削除されたファイルが出力されます.
PS > git prune -v
56266d360f3da9f922766101055bd78ffa3724bf blob
b4c96315ae08b029192fa57b46b035d0317018cc commit
c8a887332c98b8d43304c2d8c4ba0389f2665d60 tree
確認してみましょう.
PS > lat
.
└── .git
├── info
│ └── exclude
├── logs
│ └── refs
│ └── heads
├── objects
│ ├── info
│ └── pack
├── refs
│ ├── heads
│ └── tags
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
└── index
削除されていますね.
追跡されていないファイルに関しては git prune
で削除できることがわかりました.それでは追跡できるファイルはどうでしょうか.Gitはスナップショットを保存しているので、ファイルが増えれば増えるほど、バージョンが重なるたびにデータベースが肥大化していくことになります.それに対して、Gitはガベージコレクトで容量節約する機能がしっかりあります.そのコマンドは git gc
です.先ほど見た git prune
コマンドはガベージコレクトの処理の1つとして実行されるようです.
ここまでの手順をやってきた人は、ほとんど空っぽなGitリポジトリの状態になっていると思います.ガベージコレクトを試すために、再び初回コミットして、そのコミットを取り消してリセットした状態にしてください.
PS > echo 'My Project' > README.md
PS > git add README.md
PS > git commit -m "first commit"
PS > git update-ref -d HEAD
PS > git reset --hard
PS > lat
.
└── .git
├── info
│ └── exclude
├── logs
│ ├── refs
│ │ └── heads
│ └── HEAD
├── objects
│ ├── 56
│ │ └── 266d360f3da9f922766101055bd78ffa3724bf
│ ├── 81
│ │ └── 1993fddcde91487288bcccd3016971cab6c7a4
│ ├── c8
│ │ └── a887332c98b8d43304c2d8c4ba0389f2665d60
│ ├── info
│ └── pack
├── refs
│ ├── heads
│ └── tags
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
└── index
reflogは残した状態です.データベースにあるGitオブジェクトは追跡可能なので、 git prune
コマンドでは消せません.この状態で、 git gc
コマンドを実行しましょう.
PS > git gc
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Writing objects: 100% (4/4), done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
4つのオブジェクトが処理されたようです.確認してみましょう.
PS > lat
.
└── .git
├── info
│ ├── exclude
│ └── refs
├── logs
│ ├── refs
│ │ └── heads
│ └── HEAD
├── objects
│ ├── info
│ │ └── packs
│ └── pack
│ ├── pack-c3e54044977a6ee8b9652fd225f51978c072b92c.idx
│ └── pack-c3e54044977a6ee8b9652fd225f51978c072b92c.pack
├── refs
│ ├── heads
│ └── tags
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── index
└── packed-refs
いくつかファイルが追加されています.
PS > laf | %{ $_.Name }
.git\info\refs
.git\objects\info\packs
.git\objects\pack\pack-c3e54044977a6ee8b9652fd225f51978c072b92c.idx
.git\objects\pack\pack-c3e54044977a6ee8b9652fd225f51978c072b92c.pack
.git\logs\HEAD
.git\packed-refs
...
🔹 (info/refs)
ここにはブランチの一覧が格納されています.今回の例では特に関係がありません.サイズも 0 です.
🔹 objects/info/packs
ファイルの中身は次のようになっています.
PS > cat .git\objects\info\packs
P pack-c3e54044977a6ee8b9652fd225f51978c072b92c.pack
pack-c3e54044977a6ee8b9652fd225f51978c072b92c.pack
を参照しているようです.
🔹 objects/pack
2つのファイルが追加されています.
- pack-c3e54044977a6ee8b9652fd225f51978c072b92c.idx
- pack-c3e54044977a6ee8b9652fd225f51978c072b92c.pack
これらは packfile
と呼ばれるものです.これはGitオブジェクトを1つのバイナリファイル(.pack)にまとめたものと、そのインデックスファイル(.idx)です.blobオブジェクトはファイルのスナップショットです.最初はファイルの完全なデータが含まれています.このようなオブジェクトのことを loose object
といいます.Gitはガベージコレクトでloose objectをバイナリファイルにまとめます.その際、似たような名前とサイズのファイルを探して、ファイルのあるバージョンから次のバージョンまでの差分を格納します.これで容量を節約します.packfileは git verify-pack
コマンドで中身を確認できます. -v
を指定し詳細を表示してみましょう. git verify-pack
コマンドにはpackfileのインデックスファイルを指定します.
PS > git verify-pack -v .\.git\objects\pack\pack-c3e54044977a6ee8b9652fd225f51978c072b92c.idx
d566fe024bafa6e4e7be6bd429ee1a96010f3fba commit 175 118 12
4b825dc642cb6eb9a060e54bf8d69288fbee4904 tree 0 9 130
c8a887332c98b8d43304c2d8c4ba0389f2665d60 tree 37 47 139
56266d360f3da9f922766101055bd78ffa3724bf blob 11 20 186
non delta: 4 objects
.\.git\objects\pack\pack-c3e54044977a6ee8b9652fd225f51978c072b92c.pack: ok
目録や差分を格納したかどうか、対応するバイナリファイルの情報が表示されています.このようにガベージコレクトを実行することで容量の節約ができるわけです.ガベージコレクトは定期的に実行されます.また、リポジトリの更新頻度が高いとガベージコレクトを促すプロンプトが出力された気がします.
🔹 logs/HEAD
packfileの内容によって情報が書き換わっています.
0000000000000000000000000000000000000000 d566fe024bafa6e4e7be6bd429ee1a96010f3fba mebiusbox <mebiusbox@gmail.com> 1676302779 +0900 commit (initial): first commit
d566fe024bafa6e4e7be6bd429ee1a96010f3fba 0000000000000000000000000000000000000000 mebiusbox <mebiusbox@gmail.com> 1676302795 +0900
🔹 packed-refs
.git/refs
ディレクトリにある情報が packed-refs
ファイルにまとめられます.
📌 .git/ORIG_HEAD
コミットを行うと、その前の有効なHEADがORIG_HEADに記録されます.これを使えば、1つ前のHEADに戻すことができます.
PS > git reset --hard ORIG_HEAD