-
1. 開始
-
2. Git 基礎
-
3. Git 分支
-
4. 伺服器上的 Git
- 4.1 協定
- 4.2 在伺服器上安裝 Git
- 4.3 產生您的 SSH 公開金鑰
- 4.4 設定伺服器
- 4.5 Git Daemon
- 4.6 智慧 HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方託管選項
- 4.10 總結
-
5. 分散式 Git
-
A1. 附錄 A:其他環境中的 Git
- A1.1 圖形介面
- A1.2 Visual Studio 中的 Git
- A1.3 Visual Studio Code 中的 Git
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git
- A1.5 Sublime Text 中的 Git
- A1.6 Bash 中的 Git
- A1.7 Zsh 中的 Git
- A1.8 PowerShell 中的 Git
- A1.9 總結
-
A2. 附錄 B:在您的應用程式中嵌入 Git
-
A3. 附錄 C:Git 命令
A2.2 附錄 B:在您的應用程式中嵌入 Git - Libgit2
Libgit2
您可以使用的另一個選項是使用 Libgit2。Libgit2 是 Git 的一個不需依賴項目的實作,重點在於擁有一個可以在其他程式內使用的良好 API。您可以在 https://libgit2.org 找到它。
首先,讓我們看一下 C API 的樣子。這是一個快速瀏覽
// Open a repository
git_repository *repo;
int error = git_repository_open(&repo, "/path/to/repository");
// Dereference HEAD to a commit
git_object *head_commit;
error = git_revparse_single(&head_commit, repo, "HEAD^{commit}");
git_commit *commit = (git_commit*)head_commit;
// Print some of the commit's properties
printf("%s", git_commit_message(commit));
const git_signature *author = git_commit_author(commit);
printf("%s <%s>\n", author->name, author->email);
const git_oid *tree_id = git_commit_tree_id(commit);
// Cleanup
git_commit_free(commit);
git_repository_free(repo);
前幾行會開啟一個 Git 儲存庫。`git_repository` 型別代表儲存庫的句柄,並在記憶體中具有快取。這是最簡單的方法,適用於您知道儲存庫的工作目錄或 `.git` 資料夾的確切路徑時。還有 `git_repository_open_ext`,其中包含搜尋選項、`git_clone` 和其相關函數,用於建立遠端儲存庫的本地複製,以及 `git_repository_init` 用於建立全新的儲存庫。
第二段程式碼使用 rev-parse 語法(有關此語法的更多資訊,請參閱 分支參考)來取得 HEAD 最終指向的提交。返回的型別是 `git_object` 指標,代表儲存庫的 Git 物件資料庫中存在的某個物件。`git_object` 實際上是數種不同物件的「父」型別;每個「子」型別的記憶體配置與 `git_object` 相同,因此您可以安全地強制轉換為正確的型別。在此情況下,`git_object_type(commit)` 將返回 `GIT_OBJ_COMMIT`,因此可以安全地強制轉換為 `git_commit` 指標。
下一段程式碼顯示如何存取提交的屬性。此處的最後一行使用 `git_oid` 型別;這是 Libgit2 用於表示 SHA-1 雜湊的表示法。
從這個範例中,開始出現了幾個模式
-
如果您宣告一個指標並將其參考傳遞到 Libgit2 呼叫中,則該呼叫可能會返回一個整數錯誤代碼。`0` 值表示成功;任何小於 0 的值都是錯誤。
-
如果 Libgit2 為您填寫了一個指標,則您有責任釋放它。
-
如果 Libgit2 從呼叫中返回 `const` 指標,則您不必釋放它,但是當它所屬的物件被釋放時,它將變為無效。
-
編寫 C 有點痛苦。
最後一點表示在使用 Libgit2 時,您不太可能編寫 C。幸運的是,有許多特定於語言的繫結可供使用,這使得從您特定的語言和環境中使用 Git 儲存庫變得相當容易。讓我們看看使用 Libgit2 的 Ruby 繫結(名為 Rugged,可以在 https://github.com/libgit2/rugged 中找到)編寫的上述範例。
repo = Rugged::Repository.new('path/to/repository')
commit = repo.head.target
puts commit.message
puts "#{commit.author[:name]} <#{commit.author[:email]}>"
tree = commit.tree
如您所見,程式碼簡潔許多。首先,Rugged 使用例外處理;它會引發諸如 ConfigError
或 ObjectError
之類的錯誤來表示錯誤狀況。其次,由於 Ruby 具備垃圾回收機制,因此無需顯式釋放資源。讓我們來看一個稍微複雜的範例:從頭開始建立一個 commit。
blob_id = repo.write("Blob contents", :blob) # (1)
index = repo.index
index.read_tree(repo.head.target.tree)
index.add(:path => 'newfile.txt', :oid => blob_id) # (2)
sig = {
:email => "bob@example.com",
:name => "Bob User",
:time => Time.now,
}
commit_id = Rugged::Commit.create(repo,
:tree => index.write_tree(repo), # (3)
:author => sig,
:committer => sig, # (4)
:message => "Add newfile.txt", # (5)
:parents => repo.empty? ? [] : [ repo.head.target ].compact, # (6)
:update_ref => 'HEAD', # (7)
)
commit = repo.lookup(commit_id) # (8)
-
建立一個新的 blob,其中包含新檔案的內容。
-
使用 head commit 的樹狀結構填入索引,並在路徑
newfile.txt
加入新檔案。 -
這會在 ODB 中建立一個新的樹狀結構,並將其用於新的 commit。
-
作者和提交者欄位都使用相同的簽名。
-
commit 訊息。
-
建立 commit 時,您必須指定新 commit 的父 commit。此範例使用 HEAD 的頂端作為單一父 commit。
-
Rugged (和 Libgit2) 可以在建立 commit 時選擇性地更新參考。
-
傳回值是新 commit 物件的 SHA-1 雜湊值,您之後可以使用它來取得
Commit
物件。
Ruby 程式碼簡潔易讀,但由於 Libgit2 負責繁重的工作,因此這段程式碼的執行速度也相當快。如果您不是 Ruby 開發者,我們會在其他綁定中介紹其他一些綁定。
進階功能
Libgit2 具有一些超出核心 Git 範圍的功能。其中一個例子是可外掛性:Libgit2 允許您為幾種操作類型提供自訂的「後端」,因此您可以採用與標準 Git 不同的方式來儲存內容。Libgit2 允許自訂配置、參考儲存和物件資料庫等後端。
讓我們看看這是如何運作的。以下程式碼借鑒自 Libgit2 團隊提供的後端範例集 (可在 https://github.com/libgit2/libgit2-backends 中找到)。以下說明如何設定物件資料庫的自訂後端
git_odb *odb;
int error = git_odb_new(&odb); // (1)
git_odb_backend *my_backend;
error = git_odb_backend_mine(&my_backend, /*…*/); // (2)
error = git_odb_add_backend(odb, my_backend, 1); // (3)
git_repository *repo;
error = git_repository_open(&repo, "some-path");
error = git_repository_set_odb(repo, odb); // (4)
請注意,錯誤會被捕獲,但不會被處理。我們希望您的程式碼比我們的更好。
-
初始化一個空的物件資料庫 (ODB)「前端」,它將作為「後端」的容器,而後端是實際執行工作的程式碼。
-
初始化自訂 ODB 後端。
-
將後端加入前端。
-
開啟一個儲存庫,並設定它使用我們的 ODB 來查詢物件。
但是這個 git_odb_backend_mine
是什麼?嗯,它是您自己 ODB 實作的建構函式,只要您正確填寫 git_odb_backend
結構,就可以在其中執行任何您想要的操作。以下是它可能的樣子
typedef struct {
git_odb_backend parent;
// Some other stuff
void *custom_context;
} my_backend_struct;
int git_odb_backend_mine(git_odb_backend **backend_out, /*…*/)
{
my_backend_struct *backend;
backend = calloc(1, sizeof (my_backend_struct));
backend->custom_context = …;
backend->parent.read = &my_backend__read;
backend->parent.read_prefix = &my_backend__read_prefix;
backend->parent.read_header = &my_backend__read_header;
// …
*backend_out = (git_odb_backend *) backend;
return GIT_SUCCESS;
}
這裡最細微的約束是 my_backend_struct
的第一個成員必須是 git_odb_backend
結構;這可確保記憶體佈局符合 Libgit2 程式碼的預期。其餘部分是任意的;這個結構可以根據您的需要設定為任何大小。
初始化函式會為結構配置一些記憶體、設定自訂內容,然後填入它所支援的 parent
結構的成員。請參閱 Libgit2 原始碼中的 include/git2/sys/odb_backend.h
檔案,以取得完整的呼叫簽章集;您的特定使用案例將有助於判斷您需要支援哪些簽章。
其他綁定
Libgit2 具有許多語言的綁定。在這裡,我們展示了一個小型範例,使用了一些在撰寫本文時較完整的綁定套件;許多其他語言 (包括 C++、Go、Node.js、Erlang 和 JVM) 都存在函式庫,但都處於不同的成熟階段。您可以瀏覽 https://github.com/libgit2 的儲存庫來找到官方的綁定集合。我們將編寫的程式碼將從最終由 HEAD 指向的 commit 返回 commit 訊息 (有點像 git log -1
)。
LibGit2Sharp
如果您正在編寫 .NET 或 Mono 應用程式,LibGit2Sharp (https://github.com/libgit2/libgit2sharp) 就是您所需要的。這些綁定是以 C# 編寫的,並且已仔細處理以使用原生 CLR API 包裝原始 Libgit2 呼叫。以下是我們的範例程式的樣子
new Repository(@"C:\path\to\repo").Head.Tip.Message;
對於桌面 Windows 應用程式,甚至有一個 NuGet 套件可以幫助您快速入門。
objective-git
如果您的應用程式在 Apple 平台上執行,您很可能使用 Objective-C 作為實作語言。Objective-Git (https://github.com/libgit2/objective-git) 是該環境的 Libgit2 綁定的名稱。範例程式如下
GTRepository *repo =
[[GTRepository alloc] initWithURL:[NSURL fileURLWithPath: @"/path/to/repo"] error:NULL];
NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget] message];
Objective-git 與 Swift 完全可互通,因此如果您已經拋棄 Objective-C,也不必擔心。
pygit2
Python 中 Libgit2 的綁定稱為 Pygit2,可以在 https://www.pygit2.org 中找到。我們的範例程式
pygit2.Repository("/path/to/repo") # open repository
.head # get the current branch
.peel(pygit2.Commit) # walk down to the commit
.message # read the message
延伸閱讀
當然,完整闡述 Libgit2 的功能超出了本書的範圍。如果您想了解有關 Libgit2 本身的更多資訊,請參閱 https://libgit2.github.com/libgit2 的 API 文件,以及 https://libgit2.github.com/docs 的指南集。至於其他綁定,請查看隨附的 README 和測試;其中通常會有小型教學課程和進一步閱讀的指引。