最近了解了一點 Git 的內部原理,看到了一個特殊的 hash,所以寫了這一篇文章來分享自己的看法。
==============
既然你讀這篇文章,那就意味著你應該比較熟悉 Git 的一系列操作,不過,在你使用 Git 的時候,你有沒有遇到以下 hash:
4b825dc642cb6eb9a060e54bf8d69288fbee4904
可能你會覺得 git 中的每個對象都有一個 hash 值,誰會注意 hash 的數值。確實,沒有人會注意。
但是上面的這個 hash 確實是一個很特別的 hash,接下來就來說明為什麼這個 hash 是一個特殊的存在。
git 中 hash 從哪裡來?#
每個 git 存儲庫,即使是空存儲庫也將包含這段 hash。這可以通過 git show 驗證:
$ git show 4b825dc642cb6eb9a060e54bf8d69288fbee4904
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
那麼這個 hash 是從哪裡來的呢?在這之前我們需要了解一點 Git 的知識:Git 的核心部分是一個簡單的鍵值對數據庫(key-value data store)。 你可以向 Git 倉庫中插入任意類型的內容,它會返回一個唯一的鍵,通過該鍵可以在任意時刻再次取回該內容。
我們可以使用git hash-object
命令來存儲一個對象並獲取該對象的鍵。
$ echo 'test' | git hash-object -w --stdin
9daeafb9864cf43055ae93beb0afd6c7d144bfa4
Git 內部存儲的數據類似下面這樣,其中每個對象都有其對應的 hash 值:
ps:如果你仍然好奇,Pro Git 的 Git Internals 章節有更多詳細介紹。
那麼接下來說正題,這個特殊 hash 是如何產生的呢?它實際上是一棵空樹的哈希值。可以通過為空字符串的/dev/null
創建對象哈希來驗證:
$ git hash-object -t tree /dev/null
4b825dc642cb6eb9a060e54bf8d69288fbee4904
//或者
$ echo -n '' | git hash-object -t tree --stdin
4b825dc642cb6eb9a060e54bf8d69288fbee4904
空樹 hash 的特殊用處#
空樹 hash 可以與git diff
一起使用。例如,如果你想檢查目錄中的空白錯誤,您可以使用 --check
選項並將 HEAD 與空樹進行比較:
$ echo "test " > readme.md
$ git add . && git commit -m "init"
[master 6d8e897] init
1 file changed, 1 insertion(+), 3 deletions(-)
$ git diff $(git hash-object -t tree /dev/null) HEAD --check -- readme.md
readme.md:1: trailing whitespace.
+test
在編寫 git hooks
時,空樹 hash 也非常有用。一個相當常見的用法是在使用類似於以下的代碼在接受新提交之前驗證它們:
for changed_file in $(git diff --cached --name-only --diff-filter=ACM HEAD)
do
if ! validate_file "$changed_file"; then
echo "Aborting commit"
exit 1
fi
done
如果有以前的提交,這可以正常工作,但是如果沒有提交,則 HEAD
引用將不存在。為了解決這個問題,可以在檢查初始提交時使用空樹 hash:
if git rev-parse --verify -q HEAD > /dev/null; then
against=HEAD
else
# Initial commit: diff against an empty tree object
against="$(git hash-object -t tree /dev/null)"
fi
for changed_file in $(git diff --cached --name-only --diff-filter=ACM "$against")
do
if ! validate_file "$changed_file"; then
echo "Aborting commit"
exit 1
fi
done
參考#
https://floatingoctothorpe.uk/2017/empty-trees-in-git.html
首發於個人博客:方寸之間