# Outline
一、前言
二、實驗
三、小結
A、待敘項目
# TL;DR
...
# Updated
2019-10-06: 更新文章結構
在雙十連假前,此系列文每天的發文時都會以最簡陳述為主,以求在繁忙的日常中,至少能先維持挑戰鐵人賽的進度,並且逐漸拓展思路與系列結構。預期會在國慶連假將本篇文章論述完整。
常說 Git 不是記錄差異,而是紀錄快照。透過前幾天的說明,我們了解 Git 的會為每一個內文不同的檔案進行記錄,然後每個 Commit 其實只是指向了不同的 Tree Object,所以的確就像是為每個版本拍一張照片一樣。
那麼 Git 又是怎麼紀錄當前更動但還沒 commit 的狀態呢?其實前天文章的某個目錄結構就有讓這個重要角色露臉了,那就是 .git/index
這個檔案,讓我先回憶一下當時的結構吧!
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
$ tree .git/
.git/
├── COMMIT_EDITMSG
├── HEAD
├── index
├── logs
│ └── ......
├── objects
│ └── ......
└── refs
└── heads
└── master
Index 是一個二進位檔案,無法透過 cat
去解析,若真的要暸解這個檔案記錄了什麼,就只能透過 Git 提供的另一個指令 —— git ls-file
:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
$ git ls-files --stage
100644 a2beefd59223ea16000788d77e62f96bdaf23c7c 0 README.md
100644 4228d0cd48b9ed4395a23641c6292442b1af4994 0 src/app.rb
透過了這個指令,我們看到裡頭紀錄了該檔案的權限、對應 Git Object 的 SHA-1 值、以及對應的目錄位址。
這時候如果我們做了一些變動,像是新增、修改、刪除,在尚未把變動加入 index 時,index 檔案紀錄的資訊是沒有變化的:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
$ echo 'puts "Yo"' >> src/app.rb
$ echo '# Model' >> src/model.rb
$ rm README.md
$ git ls-files --stage
100644 a2beefd59223ea16000788d77e62f96bdaf23c7c 0 README.md
100644 4228d0cd48b9ed4395a23641c6292442b1af4994 0 src/app.rb
但當我們加入 index 後,得出來的結構就更新了:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
$ git add ./
$ git ls-files --stage
100644 bfdb6da6fc74e47e4328b1f60d55b3522d354c5d 0 src/app.rb
100644 50d91a6239ed5052fb5d5cdd3c4162d82161502d 0 src/model.rb
而同時,這些變動過的檔案也會以 Git Blob Object 儲存起來:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
$ tree .git/objects/
.git/objects/
├── 42
│ └── 28d0cd48b9ed4395a23641c6292442b1af4994
├── 45
│ └── 1a871aa3a41aa0019cbe48980f18580efd6c7c
├── 50
│ └── d91a6239ed5052fb5d5cdd3c4162d82161502d
├── 65
│ └── 0e0dd9f112a14a0be19b3143a5eacee882e1bb
├── 8e
│ └── f377c8dc629dd200fa03aa10a48fb1a3efca19
├── a2
│ └── beefd59223ea16000788d77e62f96bdaf23c7c
├── b4
│ └── 2533e454e5d2692d7f0d96e2a8ed699de200e8
├── bf
│ └── db6da6fc74e47e4328b1f60d55b3522d354c5d
├── cb
│ └── 089cd89a7d7686d284d8761201649346b5aa1c
├── f4
│ └── 7eca7b5d0a157583076c66d470b1eb032822ac
├── fa
│ └── 5e6af79e30fc26ab4acbd96388fde22b4c2f36
└── fd
└── d241767aec1614be16cd718e5baae6ba0cab4b
所以其實 Git 是一個不斷新增的版本控制系統,Git 不會刪除被記錄下來的檔案,有修改過的檔案都會被當作新的檔案被加入,然後再重新指向到新檔案而已。
透過 index 紀錄的資訊以及當前 commit 的 Tree Object,Git 就可以比對出差異,有 index 與 commit 的差異,也有 index 和當前 Workspace 的差異。