轉發學習的啦。
似乎很少有人在讀某個git快速教程的時候會說:“這個關於git的快速教程太酷了!讀完了用起git來超級舒服,並且我一點也不怕自己會破壞什么東西。”
對git的初學者來說,剛接觸git時就像進入了一個他不會聽/說當地語言的陌生國度。如果你知道自己在哪里並且知道怎么走,那就很好。但是如果你迷路了,那麻煩就大了。
市面上已經有很多關於學習git基本指令的文章,因此這篇文章不講這個。這里我們將試着從不同的角度來理解。
新手們通常都很害怕git,的確,git確實是一個很強大的工具,但它對使用者並不友好。大量的新概念,一個指令在不同的情況下做完全不同的事情,各種隱含的反饋……
我認為克服這個困難的一個可行方法就是在git的日常commit/puah之外再多做一點工作,如果花點時間來理解一下git是如何產生的,能幫我們避免很多麻煩。
理解.git
當你建立了一個git repo,使用git init,git便創建了一個奇妙的目錄:.git
這個文件夾里包含了git工作時所需要的所有信息。需要明確的是,如果想從你的項目中移除git,但保留項目文件,只需要刪除.git文件夾即可。但是,為什么要這樣做呢?
└── tags
這是你第一次commit之前.git文件夾的樣子。
HEAD:這個我們稍后再說。
config:這個文件夾里是你的保存設置,這里將寫入遠程URL,比如你的郵箱、用戶名等。每一次在控制端使用“git config”,它都會在這里結束。
description:被gitweb (Github的原型)用來顯示對repo的描述。
hooks:這里有一個有趣的特性。Git有一套可以自動運行在任何一個有意義的git階段下的腳本,叫做hooks。hooks可以運行在commit/rebase/pull等等狀態的之前或之后。腳本的名稱決定了它什么時候被執行。一個有用的pre-push腳本的例子將會被運行以測試控制器(遠程控制)中的所有樣式規則保持一致。
info - exclude:可以將你不想被git處理的文件放到.gitignore文件夾里。被排除的文件可以做到相同的事情,除了它不能被共享。如果你不想將你的自定義IDE關聯到congif文件里,就可以使用這個。雖然大部分情況下,.gitignore就足夠了。
commit的內部是什么?
每次你創建了一個文件並跟蹤它,git都會將其壓縮並存儲到自己的數據結構中。這個壓縮對象有一個獨特的名字、一個哈希碼,存儲在對象目錄下。
在研究對象目錄前,我們要問一個問題,什么是commit。這里commit可以看做是工作目錄的一種快照,但不僅僅是快照。
實際上當你commit時,git只做兩件事情來創造你工作目錄的快照:
如果文件沒有修改,git僅僅增加壓縮文件的名字(hash)到快照中。
如果文件被修改過,git就將其壓縮,再將壓縮后的文件存儲到對象文件夾中。然后再添加這個壓縮文件的文件名(hash)到快照中去。
這是一個簡化的描述,實際整個過程會復雜一點。
一旦快照文件被建立,它也會被壓縮並用hash文件命名。那么這些壓縮文件在什么地方呢?答案:對象文件夾。
|── 4c
| └── f44f1e3fe4fb7f8aa42138c324f63f5ac85828 // hash
|── 86
| └── 550c31847e518e1927f95991c949fc14efc711 // hash
|── e6
| └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 // hash
|── info
└── pack
當我創建了一個名為file_1.txt的空文件並commit之后,對象目錄應該是如上所看到的樣子。請注意如果你的文件的哈希碼是“89faaee…”,git將會吧這個文件儲存在名為“89”的子目錄下,並且命名這個文件為“faaee…”。
你看到右邊有3個hash字樣。一個對應的是我的file_1.txt文件,另一個對應的是我commit時所創建的快照文件。那么第三個呢?這是因為commit本身也是一個對象,它也會被壓縮並被存儲在對象文件夾中。
記住,一個commit指令實際上包含4件事:
工作目錄的快照文件的名稱(哈希碼)
注釋
提交者信息
Parent commit的哈希碼
然后,你們可以自己看一下如果不壓縮commit文件時會發生什么:
// 查看歷史,你會很容易就找到你的commit哈希碼
// 你也不必粘貼全部的哈希碼,只要足夠就可以了
// 創造了獨特哈希碼的字符串
git cat-file -p 4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828
得到結果:
tree 86550c31847e518e1927f95991c949fc14efc711
author Pierre De Wulf <test@gmail.com> 1455775173 -0500
committer Pierre De Wulf <test@gmail.com> 1455775173 -0500
commit A
你看,正如我們所期望的,我們得到了快照文件的哈希碼、作者信息、和我的commit信息。
這里有兩件很重要的事情:
-
正如所期望的,那個名為“86550…”的快照哈希文件也是一個對象,並且能夠在對象文件夾中被找到。
-
因為這是我的第一個commit,所以沒有Parent。
快照文件本質上是什么呢?
git cat-file -p 86550c31847e518e1927f95991c949fc14efc711
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file_1.txt
這里,我們找到我們對象存儲器中之前存儲的最后一個對象,我們快照文件中僅有的對象。這是一個blob,但不是我們今天要講的。
分支、標簽、HEAD,它們都一樣。