<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hant-TW">
	<id>https://jiva.dila.edu.tw/index.php?action=history&amp;feed=atom&amp;title=Pro_Git_9.2_Git_%E7%89%A9%E4%BB%B6</id>
	<title>Pro Git 9.2 Git 物件 - 修訂歷史</title>
	<link rel="self" type="application/atom+xml" href="https://jiva.dila.edu.tw/index.php?action=history&amp;feed=atom&amp;title=Pro_Git_9.2_Git_%E7%89%A9%E4%BB%B6"/>
	<link rel="alternate" type="text/html" href="https://jiva.dila.edu.tw/index.php?title=Pro_Git_9.2_Git_%E7%89%A9%E4%BB%B6&amp;action=history"/>
	<updated>2026-05-05T12:44:42Z</updated>
	<subtitle>本 Wiki 上此頁面的修訂歷史</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://jiva.dila.edu.tw/index.php?title=Pro_Git_9.2_Git_%E7%89%A9%E4%BB%B6&amp;diff=589&amp;oldid=prev</id>
		<title>imported&gt;Ray：​新頁面: Git 是一套內容定址檔案系統。很不錯。不過這是什麼意思呢？  這種說法的意思是，從內部來看，Git 是簡單的 key-value 資料儲存。它允許插入...</title>
		<link rel="alternate" type="text/html" href="https://jiva.dila.edu.tw/index.php?title=Pro_Git_9.2_Git_%E7%89%A9%E4%BB%B6&amp;diff=589&amp;oldid=prev"/>
		<updated>2011-06-27T03:59:30Z</updated>

		<summary type="html">&lt;p&gt;新頁面: Git 是一套內容定址檔案系統。很不錯。不過這是什麼意思呢？  這種說法的意思是，從內部來看，Git 是簡單的 key-value 資料儲存。它允許插入...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新頁面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Git 是一套內容定址檔案系統。很不錯。不過這是什麼意思呢？&lt;br /&gt;
&lt;br /&gt;
這種說法的意思是，從內部來看，Git 是簡單的 key-value 資料儲存。它允許插入任意類型的內容，並會回傳一個鍵值，通過該鍵值可以在任何時候再取出該內容。可以通過底層命令 hash-object 來示範這點，傳一些資料給該命令，它會將資料保存在 .git 目錄並回傳表示這些資料的鍵值。首先初使化一個 Git 倉庫並確認 objects 目錄是空的：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ mkdir test&lt;br /&gt;
$ cd test&lt;br /&gt;
$ git init&lt;br /&gt;
Initialized empty Git repository in /tmp/test/.git/&lt;br /&gt;
$ find .git/objects&lt;br /&gt;
.git/objects&lt;br /&gt;
.git/objects/info&lt;br /&gt;
.git/objects/pack&lt;br /&gt;
$ find .git/objects -type f&lt;br /&gt;
$&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Git 初始化了 objects 目錄，同時在該目錄下創建了 pack 和 info 子目錄，但是該目錄下沒有其他常規檔。我們往這個 Git 資料庫裡儲存一些文本：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ echo 'test content' | git hash-object -w --stdin&lt;br /&gt;
d670460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
參數 -w 指示 hash-object 命令儲存 (資料) 物件，若不指定這個參數該命令僅僅回傳鍵值。--stdin 指定從標準輸入裝置 (stdin) 來讀取內容，若不指定這個參數則需指定一個要儲存的檔案路徑。該命令輸出長度為 40 個字元的校驗和(checksum hash)。這是個 SHA-1 雜湊值──其值為要儲存的資料加上你馬上會瞭解到的一種頭資訊(header)的校驗和。現在可以查看到 Git 已經儲存了資料：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ find .git/objects -type f&lt;br /&gt;
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
可以在 objects 目錄下看到一個檔。這便是 Git 儲存資料內容的方式──為每份內容生成一個檔，取得該內容與頭資訊的 SHA-1 校驗和，創建以該校驗和前兩個字元為名稱的子目錄，並以 (校驗和) 剩下 38 個字元為檔命名 (保存至子目錄下)。&lt;br /&gt;
&lt;br /&gt;
通過 cat-file 命令可以將資料內容取回。該命令是查看 Git 對象的瑞士軍刀。傳入 -p 參數可以讓該命令輸出資料內容的類型：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;
test content&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
可以往 Git 中添加更多內容並取回了。也可以直接添加檔案。比方說可以對一個檔進行簡單的版本控制。首先，創建一個新檔，並把檔案內容儲存到資料庫中：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ echo 'version 1' &amp;gt; test.txt&lt;br /&gt;
$ git hash-object -w test.txt&lt;br /&gt;
83baae61804e65cc73a7201a7252750c76066a30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
接著往該檔中寫入一些新內容並再次保存：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ echo 'version 2' &amp;gt; test.txt&lt;br /&gt;
$ git hash-object -w test.txt&lt;br /&gt;
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
資料庫中已經將檔案的兩個新版本連同一開始的內容保存下來了：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ find .git/objects -type f&lt;br /&gt;
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a&lt;br /&gt;
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30&lt;br /&gt;
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
再將檔案修復到第一個版本：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 &amp;gt; test.txt&lt;br /&gt;
$ cat test.txt&lt;br /&gt;
version 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
或恢復到第二個版本：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a &amp;gt; test.txt&lt;br /&gt;
$ cat test.txt&lt;br /&gt;
version 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
需要記住的是幾個版本的檔 SHA-1 值可能與實際的值不同，其次，儲存的並不是檔案名而僅僅是檔案內容。這種物件類型稱為 blob 。通過傳遞 SHA-1 值給 cat-file -t 命令可以讓 Git 返回任何物件的類型：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a&lt;br /&gt;
blob&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=tree 物件=&lt;br /&gt;
&lt;br /&gt;
接下去來看 tree 物件，tree 物件可以儲存檔案名，同時也允許將一組檔案儲存在一起。Git 以一種類似 UNIX 檔案系統但更簡單的方式來儲存內容。所有內容以 tree 或 blob 物件存儲，其中 tree 物件對應於 UNIX 中的目錄，blob 物件則大致對應於 inodes 或檔案內容。一個單獨的 tree 物件包含一條或多條 tree 記錄，每一條記錄含有一個指向 blob 或子 tree 物件的 SHA-1 指標，並附有該物件的許可權模式 (mode)、類型和檔案名資訊。以 simplegit 專案為例，最新的 tree 可能是這個樣子：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git cat-file -p master^{tree}&lt;br /&gt;
100644 blob a906cb2a4a904a152e80877d4088654daad0c859      README&lt;br /&gt;
100644 blob 8f94139338f9404f26296befa88755fc2598c289      Rakefile&lt;br /&gt;
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      lib&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
master^{tree} 表示 branch 分支上最新提交指向的 tree 物件。請注意 lib 子目錄並非一個 blob 物件，而是一個指向別一個 tree 物件的指標：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0&lt;br /&gt;
100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b      simplegit.rb&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
從概念上來講，Git 保存的資料如圖 9-1 所示。&lt;br /&gt;
&lt;br /&gt;
[[圖片:Pro-git-9-1.png]]&lt;br /&gt;
Figure 9-1. Git 物件模型的簡化版&lt;br /&gt;
&lt;br /&gt;
你可以自己創建 tree 。通常 Git 根據你的暫存區域或 index 來創建並寫入一個 tree 。因此要創建一個 tree 物件的話首先要通過將一些檔暫存從而創建一個 index 。可以使用 plumbing 命令 update-index 為一個單獨檔 ── test.txt 檔的第一個版本 ──　創建一個 index。通過該命令人工地將 test.txt 檔的首個版本加入到了一個新的暫存區域中。由於該檔原先並不在暫存區域中 (甚至就連暫存區域也還沒被創建出來呢)，必須傳入 --add 參數；由於要添加的檔並不在目前的目錄下而是在資料庫中，必須傳入 --cacheinfo 參數。同時指定了檔模式，SHA-1 值和檔案名：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git update-index --add --cacheinfo 100644 \&lt;br /&gt;
  83baae61804e65cc73a7201a7252750c76066a30 test.txt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
在本例中，指定了檔案模式為 100644，表明這是一個普通檔。其他可用的模式有：100755 表示可執行檔，120000 表示符號連結。檔案模式是從一般的 UNIX 檔案模式中參考來的，但是沒有那麼靈活 ── 上述三種模式僅對 Git 中的檔 (blobs) 有效 (雖然也有其他模式用於目錄和子模組)。&lt;br /&gt;
&lt;br /&gt;
現在可以用 write-tree 命令將暫存區域的內容寫到一個 tree 物件了。無需 -w 參數 ── 如果目標 tree 不存在，呼叫 write-tree 會自動根據 index 狀態創建一個 tree 物件。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git write-tree&lt;br /&gt;
d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;
100644 blob 83baae61804e65cc73a7201a7252750c76066a30      test.txt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
可以驗證這確實是一個 tree 物件：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;
tree&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
再根據 test.txt 的第二個版本以及一個新檔創建一個新 tree 物件：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ echo 'new file' &amp;gt; new.txt&lt;br /&gt;
$ git update-index test.txt&lt;br /&gt;
$ git update-index --add new.txt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
這時暫存區域中包含了 test.txt 的新版本及一個新檔 new.txt 。創建 (寫) 該 tree 物件 (將暫存區域或 index 狀態寫入到一個 tree 物件)，然後瞧瞧它的樣子：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git write-tree&lt;br /&gt;
0155eb4229851634a0f03eb265b69f5a2d56f341&lt;br /&gt;
$ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341&lt;br /&gt;
100644 blob fa49b077972391ad58037050f2a75f74e3671e92      new.txt&lt;br /&gt;
100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a      test.txt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
請注意該 tree 物件包含了兩個檔案記錄，且 test.txt 的 SHA 值是早先值的 “第二版” (1f7a7a)。來點更有趣的，你將把第一個 tree 物件作為一個子目錄加進該 tree 中。可以用 read-tree 命令將 tree 物件讀到暫存區域中去。在這時，通過傳一個 --prefix 參數給 read-tree，將一個已有的 tree 物件作為一個子 tree 讀到暫存區域中：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;
$ git write-tree&lt;br /&gt;
3c4e9cd789d88d8d89c1073707c3585e41b0e614&lt;br /&gt;
$ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614&lt;br /&gt;
040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579      bak&lt;br /&gt;
100644 blob fa49b077972391ad58037050f2a75f74e3671e92      new.txt&lt;br /&gt;
100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a      test.txt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
如果從剛寫入的新 tree 物件創建一個工作目錄，將得到位於工作目錄頂級的兩個檔和一個名為 bak 的子目錄，該子目錄包含了 test.txt 檔的第一個版本。可以將 Git 用來包含這些內容的資料想像成如圖 9-2 所示的樣子。&lt;br /&gt;
&lt;br /&gt;
[[圖片:Pro-git-9-2.png]]&lt;br /&gt;
Figure 9-2. 當前 Git 資料的內容結構&lt;br /&gt;
&lt;br /&gt;
=commit (提交) 物件=&lt;br /&gt;
&lt;br /&gt;
你現在有三個 tree 物件，它們指向了你要跟蹤的專案的不同快照，可是先前的問題依然存在：必須記往三個 SHA-1 值以獲得這些快照。你也沒有關於誰、何時以及為何保存了這些快照的資訊。commit 物件為你保存了這些基本資訊。&lt;br /&gt;
&lt;br /&gt;
要創建一個 commit 物件，使用 commit-tree 命令，指定一個 tree 的 SHA-1，如果有任何前繼提交物件，也可以指定。從你寫的第一個 tree 開始：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ echo 'first commit' | git commit-tree d8329f&lt;br /&gt;
fdf4fc3344e67ab068f836878b6c4951e3b15f3d&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
通過 cat-file 查看這個新 commit 物件：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git cat-file -p fdf4fc3&lt;br /&gt;
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579&lt;br /&gt;
author Scott Chacon &amp;lt;schacon@gmail.com&amp;gt; 1243040974 -0700&lt;br /&gt;
committer Scott Chacon &amp;lt;schacon@gmail.com&amp;gt; 1243040974 -0700&lt;br /&gt;
&lt;br /&gt;
first commit&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
commit 物件格式很簡單：指明了該時間點專案快照的頂層樹物件、作者/提交者資訊（從 Git 組態設定的 user.name 和 user.email中獲得)以及當前時間戳記、一個空行，以及提交注釋資訊。&lt;br /&gt;
&lt;br /&gt;
接著再寫入另外兩個 commit 物件，每一個都指定其之前的那個 commit 物件：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ echo 'second commit' | git commit-tree 0155eb -p fdf4fc3&lt;br /&gt;
cac0cab538b970a37ea1e769cbbde608743bc96d&lt;br /&gt;
$ echo 'third commit'  | git commit-tree 3c4e9c -p cac0cab&lt;br /&gt;
1a410efbd13591db07496601ebc7a059dd55cfe9&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
每一個 commit 物件都指向了你創建的樹物件快照。出乎意料的是，現在已經有了真實的 Git 歷史了，所以如果執行 git log 命令並指定最後那個 commit 物件的 SHA-1 便可以查看歷史：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git log --stat 1a410e&lt;br /&gt;
commit 1a410efbd13591db07496601ebc7a059dd55cfe9&lt;br /&gt;
Author: Scott Chacon &amp;lt;schacon@gmail.com&amp;gt;&lt;br /&gt;
Date:   Fri May 22 18:15:24 2009 -0700&lt;br /&gt;
&lt;br /&gt;
    third commit&lt;br /&gt;
&lt;br /&gt;
 bak/test.txt |    1 +&lt;br /&gt;
 1 files changed, 1 insertions(+), 0 deletions(-)&lt;br /&gt;
&lt;br /&gt;
commit cac0cab538b970a37ea1e769cbbde608743bc96d&lt;br /&gt;
Author: Scott Chacon &amp;lt;schacon@gmail.com&amp;gt;&lt;br /&gt;
Date:   Fri May 22 18:14:29 2009 -0700&lt;br /&gt;
&lt;br /&gt;
    second commit&lt;br /&gt;
&lt;br /&gt;
 new.txt  |    1 +&lt;br /&gt;
 test.txt |    2 +-&lt;br /&gt;
 2 files changed, 2 insertions(+), 1 deletions(-)&lt;br /&gt;
&lt;br /&gt;
commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d&lt;br /&gt;
Author: Scott Chacon &amp;lt;schacon@gmail.com&amp;gt;&lt;br /&gt;
Date:   Fri May 22 18:09:34 2009 -0700&lt;br /&gt;
&lt;br /&gt;
    first commit&lt;br /&gt;
&lt;br /&gt;
 test.txt |    1 +&lt;br /&gt;
 1 files changed, 1 insertions(+), 0 deletions(-)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
真棒。你剛剛通過使用低級操作而不是那些普通命令創建了一個 Git 歷史。這基本上就是執行　git add 和 git commit 命令時 Git 進行的工作　──保存修改了的檔案的 blob，更新索引，創建 tree 物件，最後創建 commit 物件，這些 commit 物件指向了頂層 tree 物件以及先前的 commit 物件。這三類 Git 物件 ── blob，tree 以及 commit ── 都各自以檔案的方式保存在 .git/objects 目錄下。以下所列是目前為止範例目錄的所有物件，每個物件後面的注釋裡標明了它們保存的內容：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ find .git/objects -type f&lt;br /&gt;
.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2&lt;br /&gt;
.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3&lt;br /&gt;
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2&lt;br /&gt;
.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3&lt;br /&gt;
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1&lt;br /&gt;
.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2&lt;br /&gt;
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'&lt;br /&gt;
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1&lt;br /&gt;
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt&lt;br /&gt;
.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
如果你按照以上描述進行了操作，可以得到如圖 9-3 所示的物件圖。&lt;br /&gt;
&lt;br /&gt;
[[圖片:Pro-git-9-3.png]]&lt;br /&gt;
Figure 9-3. Git 目錄下的所有物件&lt;br /&gt;
&lt;br /&gt;
=物件儲存=&lt;br /&gt;
&lt;br /&gt;
之前我提到當儲存資料內容時，同時會有一個檔頭被儲存起來。我們花些時間來看看 Git 是如何儲存物件的。你將看到如何通過 Ruby 指令碼語言儲存一個 blob 物件 (這裡以字串 “what is up, doc?” 為例) 。使用 irb 命令進入 Ruby 互動式模式：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ irb&lt;br /&gt;
&amp;gt;&amp;gt; content = &amp;quot;what is up, doc?&amp;quot;&lt;br /&gt;
=&amp;gt; &amp;quot;what is up, doc?&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Git 以物件類型為起始內容構造一個檔頭，本例中是一個 blob。然後添加一個空格，接著是資料內容的長度，最後是一個空位元組 (null byte)：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt; header = &amp;quot;blob #{content.length}\0&amp;quot;&lt;br /&gt;
=&amp;gt; &amp;quot;blob 16\000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Git 將檔頭與原始資料內容拼接起來，並計算拼接後的新內容的 SHA-1 校驗和。可以在 Ruby 中使用 require 語句導入 SHA1 digest 庫，然後調用 Digest::SHA1.hexdigest() 方法計算字串的 SHA-1 值：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt; store = header + content&lt;br /&gt;
=&amp;gt; &amp;quot;blob 16\000what is up, doc?&amp;quot;&lt;br /&gt;
&amp;gt;&amp;gt; require 'digest/sha1'&lt;br /&gt;
=&amp;gt; true&lt;br /&gt;
&amp;gt;&amp;gt; sha1 = Digest::SHA1.hexdigest(store)&lt;br /&gt;
=&amp;gt; &amp;quot;bd9dbf5aae1a3862dd1526723246b20206e5fc37&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Git 用 zlib 對資料內容進行壓縮，在 Ruby 中可以用 zlib 程式庫來實現。首先需要導入該程式庫，然後用 Zlib::Deflate.deflate() 對資料進行壓縮：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt; require 'zlib'&lt;br /&gt;
=&amp;gt; true&lt;br /&gt;
&amp;gt;&amp;gt; zlib_content = Zlib::Deflate.deflate(store)&lt;br /&gt;
=&amp;gt; &amp;quot;x\234K\312\311OR04c(\317H,Q\310,V(-\320QH\311O\266\a\000_\034\a\235&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
最後將用 zlib 壓縮後的內容寫入磁片。需要指定保存物件的路徑 (SHA-1 值的頭兩個字元作為子目錄名稱，剩餘 38 個字元作為檔案名保存至該子目錄中)。在 Ruby 中，如果子目錄不存在可以用 FileUtils.mkdir_p() 函數創建它。接著用 File.open 方法打開檔案，並用 write() 方法將之前壓縮的內容寫入該檔：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt; path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]&lt;br /&gt;
=&amp;gt; &amp;quot;.git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37&amp;quot;&lt;br /&gt;
&amp;gt;&amp;gt; require 'fileutils'&lt;br /&gt;
=&amp;gt; true&lt;br /&gt;
&amp;gt;&amp;gt; FileUtils.mkdir_p(File.dirname(path))&lt;br /&gt;
=&amp;gt; &amp;quot;.git/objects/bd&amp;quot;&lt;br /&gt;
&amp;gt;&amp;gt; File.open(path, 'w') { |f| f.write zlib_content }&lt;br /&gt;
=&amp;gt; 32&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
這就行了 ── 你已經創建了一個正確的 blob 物件。所有的 Git 物件都以這種方式儲存，惟一的區別是類型不同 ── 除了字串 blob，檔頭起始內容還可以是 commit 或 tree 。不過雖然 blob 幾乎可以是任意內容，commit 和 tree 的資料卻是有固定格式的。&lt;/div&gt;</summary>
		<author><name>imported&gt;Ray</name></author>
	</entry>
</feed>