Git

**git**（/ɡɪt/， 音訊，吉特）是一個分散式版本控制軟體，最初由林納斯・托瓦茲創作，於 2005 年以 GPL 授權條款釋出。最初目的是為了更好地管理 Linux 核心開發而設計。應注意的是，這與 GNU Interactive Tools（一個類似 Norton Commander 介面的檔案管理器）不同。

git 最初的開發動力來自於 BitKeeper 和 Monotone。git 最初只是作為一個可以被其他前端（比如 Cogito 或 Stgit）包裝的後端而開發的，但後來 git 核心已經成熟到可以獨立地用作版本控制。很多被廣泛使用的軟體專案都使用 git 進行版本控制，其中包括 Linux 核心、X.Org 伺服器和 OLPC 核心等專案的開發流程。

## 歷史

自 2002 年開始，林納斯・托瓦茲（Linus Torvalds）決定使用 BitKeeper 作為 Linux 核心主要的版本控制系統用以維護程式碼。因為 BitKeeper 為專有軟體，這個決定在社群中長期遭受質疑。在 Linux 社群中，特別是理察・斯托曼與自由軟體基金會的成員，主張應該使用開放原始碼的軟體來作為 Linux 核心的版本控制系統。林納斯・托瓦茲曾考慮過採用現成軟體作為版本控制系統（例如 Monotone），但這些軟體都存在一些問題，特別是效能不佳。現成的方案，如 CVS 的架構，受到林納斯・托瓦茲的批評。

2005 年，安德魯・垂鳩（Andrew Tridgell）寫了一個簡單程式，可以連接 BitKeeper 的儲存庫，BitKeeper 著作權擁有者拉里・麥沃伊認為安德魯・垂鳩對 BitKeeper 內部使用的協定進行逆向工程，決定收回無償使用 BitKeeper 的授權。Linux 核心開發團隊與 BitMover 公司進行磋商，但無法解決他們之間的歧見。林納斯・托瓦茲決定自行開發版本控制系統替代 BitKeeper，以十天的時間編寫出 git 第一個版本。

### 命名

林納斯・托瓦茲諷刺地嘲笑 git 這個名字（在英式英語俚語中表示「不愉快的人」）

原始碼的讀我檔案進一步闡述了：

> The name "git" was given by Linus Torvalds when he wrote the very first version. He described the tool as "the stupid content tracker" and the name as (depending on your way):
> 
> * random three-letter combination that is pronounceable, and not actually used by any common UNIX command. The fact that it is a mispronunciation of "get" may or may not be relevant.
> * "global information tracker": you're in a good mood, and it actually works for you. Angels sing, and a light suddenly fills the room.
> * stupid. contemptible and despicable. simple. Take your pick from the dictionary of slang.
> 
> 林納斯・托瓦茲在編寫第一個版本時就使用了「git」這個名稱。 他將工具描述為「愚蠢的內容跟蹤器」，並將其描述為（取決於您的方式）：
> 
> * 可以發音唸出的隨機三個字母組合，而且並未被實際用在任何 UNIX 指令上。它是「get」的錯誤發音，這點可能相關也可能無關。
> * 「全球資訊跟蹤器」：您的心情不錯，對你而言它也確實說得通。天使唱歌，房間突然充滿光明。
> * 愚蠢的。鄙視和卑鄙的。簡單。從俚語字典中選擇。
> 

### 版本

## 主要功能

**git** 是用於 Linux 核心開發的版本控制工具。與 CVS、Subversion 一類的集中式版本控制工具不同，它採用了分散式版本庫的作法，不需要伺服器端軟體，就可以運作版本控制，使得原始碼的釋出和交流極其方便。git 的速度很快，這對於諸如 Linux 核心這樣的大專案來說自然很重要。git 最為出色的是它的合併追蹤（merge tracing）能力。

實際上 Linux 核心開發團隊決定開始開發和使用 git 來作為核心開發的版本控制系統的時候，世界上開源社群的反對聲音不少，最大的理由是 git 太艱澀難懂，從 git 的內部工作機制來說，的確是這樣。但是隨著開發的深入，git 的正常使用都由一些友善的命令來執行，使 git 變得非常好用。現在，越來越多的著名專案採用 git 來管理專案開發，例如：wine、U-boot 等。

作為開源自由原教旨主義專案，git 沒有對版本庫的瀏覽和修改做任何的權限限制，透過其他工具也可以達到有限的權限控制，比如：gitosis、CodeBeamer MR。原本 git 的使用範圍只適用於 Linux/Unix 平台，但在 Windows 平台下的使用也日漸成熟，這主要歸功於 Cygwin、msysgit 環境，以及 TortoiseGit 這樣易用的 GUI 工具。git 的原始碼中也已經加入了對 Cygwin 與 MinGW 編譯環境的支援且逐漸完善，為 Windows 使用者帶來福音。

## 實現原理

git 和其他版本控制系統（如 CVS）有不小的差別，git 本身關心檔案的整體性是否有改變，但多數的版本控制系統如 CVS 或 Subversion 系統則在乎檔案內容的差異。git 拒絕保持每個檔案的版本修訂關係。因此檢視一個檔案的歷史需要遍歷各個 history 快照；git 隱式處理檔案更名，即同名檔案預設為其前身，如果沒有同名檔案則在前一個版本中搜尋具有類似內容的檔案。

git 更像一個檔案系統，直接在本機上取得資料，不必連線到主機端取得資料。 每個開發者都可有全部開發歷史的本機副本，changes 從這種本機 repository 複製給其他開發者。這些 changes 作為新增的開發分支被匯入，可以與本機開發分支合併。

分支是非常輕量級的，一個分支僅是對一個 commit 的參照。

git 是用 C 語言開發的，以追求最高的效能。git 自動完成垃圾回收，也可以用命令 `git gc --prune` 直接呼叫。

git 儲存每個新建立的 object 作為一個單獨檔案。為了壓縮儲存空間占用， packs 操作把很多檔案（啟發式類似名字的檔案往往具有類似內容）使用差分壓縮入一個檔案中（packfile），並建立一個對應的索引檔案，指明 object 在 packfile 中的偏移值。新建立的物件仍然作為單獨檔案存在。repacks 操作非常費時間，git 會在空閒時間自動做此操作。也可用命令 `git gc` 來直接啟動 repack。packfile 與索引檔案都用 SHA-1 作為校驗和並作為檔名。`git fsck` 命令做校驗和的完整性驗證。

Git 伺服器典型的 TCP 監聽埠為 9418。

## 儲存庫目錄

* hooks：儲存 hook 的資料夾
* logs：儲存日誌的資料夾
* refs：儲存指向各個分支的指標（SHA-1 標識）檔案
* objects：存放 git 物件
* config：存放各種組態檔
* HEAD：指向當前所在分支的指標檔案路徑，一般指向 refs 下的某檔案

## 資料結構

Git 有兩種資料結構：可變的索引（index、stage 或 cache）用於緩衝工作目錄資訊與下一次提交的版本資訊；不變的、僅追加的物件資料庫。

物件資料庫包含 4 類物件：

* blob （二進位大型物件）是使用 zlib 壓縮演算法對一個檔案的內容壓縮後的結果。Blobs 沒有儲存檔名、時間戳或其他中繼資料。Git 將其儲存在位於隱藏的.git/objects 資料夾中。檔案的名稱為使用 SHA-1 雜湊函式對原檔案內容生成的雜湊值。這些物件檔案稱為 Blob，每次將新檔案添加到儲存庫時會建立 Blob 物件。
* tree 物件對應於檔案目錄。包含檔名列表以及檔案的類型位元（包含許可權）、到 blob（對應於檔案）或 tree 物件的參照。tree 物件是源樹（source tree）的快照。用雜湊樹實作。
* commit 物件連結 tree 物件在一起而成為 history，包含頂層源目錄的 tree 物件名字、一個時間戳、log 資訊、0 個或多個父 commit 物件的名字。用於儲存特定版本的樹型資料夾結構以及提交作者，電子郵件位址，日期和描述性提交訊息。
* tag 物件是一個容器，包含了到另一個物件的參照，也可以增加關於另外物件的中繼資料。通常它儲存需要追溯的特定版本資料的一個 commit 物件的數位簽章。

以上 4 類的物件用其內容的 SHA-1 hash 值標識：hash 值的前兩個字元作為存放的目錄名字，其餘 hash 字元作為這個物件的檔名。

Git 資料庫中不變參照的物件將會被垃圾回收清除。Git 命令可以建立、移動、刪除參照。"git show-ref" 列出所有參照。某些參照類型：

* _heads_：參照一個本機物件，是 commit 的指標。每個 head 可以指任意一個這樣的指標。可以包含任意數量的 heads。而 "HEAD"（全部大寫），僅僅指的是當前有效的 head。預設情況下，在每個儲存庫下都有一個 head，叫做 master。
* _remotes_：參照遠端 repository 中的一個物件
* _stash_：參照一個還沒有 committed 的一個物件
* _meta_：例如一個 bare repository 中的一個組態，使用者權限；refs/meta/config 命名空間等
* _tags_：

某些操作（例如，將提交推播到遠端儲存庫，儲存太多物件或手動執行 Git 的垃圾收集命令）可能會導致 Git 將物件重新打包為打包檔案，在打包過程中，採用反向差異並進行壓縮以消除多餘的內容並減小尺寸。該過程將生成包含物件內容的.pack 檔案，每個檔案都有一個對應的.idx 索引檔案，其中包含對打包物件及其在打包檔案中位置的參照。當將分支推播到遠端儲存庫或從遠端儲存庫拉出分支時，這些打包檔案將透過網路傳輸。提取或取得分支時，將打包檔案解壓縮以在物件儲存庫中建立鬆散物件。

## 移植性

在 Windows 平台上有 msysgit 與 TortoiseGit 可資利用。TortoiseGit 還提供有 GUI。

Git 也提供 Windows 版本下載。

Visual Studio 自 2013 版本開始內建 Git 功能。

## GIT GUI 用戶端

* GitHub Desktop：可用於第三方 Git 儲存庫網站
* Git for Windows
* TortoiseGit
* SourceTree
* GitEye

## 使用

### 使用 git 的專案

有不少的專案目前都使用 git:

* NOJ

### 支援 git 的原始碼存取服務

以下是部分知名的支援 git 的原始碼存取服務：

* BerliOS
* Beanstalk
* Bitbucket
* CodePlex（已於 2017 年 12 月 15 日起關閉）
* GitHub
* gitorious
* GNU Savannah
* Google Code
* JavaForge
* Pikacode
* SourceForge
* 碼雲 Gitee （頁面存檔備份，存於網際網路檔案館）
* CSDN CODE
* Coding （頁面存檔備份，存於網際網路檔案館）
* GitLab

## 參見

* 分散式版本控制
* Gitee
* 代碼庫
* 儲存庫 (版本控制)
* Github

## 參考文獻

## 外部連結