A2.2 Libgit2

2018-02-24 15:23 更新

Libgit2

另外一種可以供你使用的是 Libgit2。 Libgit2 是一個(gè) Git 的非依賴性的工具,它致力于為其他程序使用 Git 提供更好的 API。 你可以在??找到它。

首先,讓我們來(lái)看一下 C API 長(zhǎng)啥樣。 這是一個(gè)旋風(fēng)式旅行。

// 打開(kāi)一個(gè)版本庫(kù)
git_repository *repo;
int error = git_repository_open(&repo, "/path/to/repository");

// 逆向引用 HEAD 到一個(gè)提交
git_object *head_commit;
error = git_revparse_single(&head_commit, repo, "HEAD^{commit}");
git_commit *commit = (git_commit*)head_commit;

// 顯示這個(gè)提交的一些詳情
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);

// 清理現(xiàn)場(chǎng)
git_commit_free(commit);
git_repository_free(repo);

前兩行打開(kāi)一個(gè) Git 版本庫(kù)。 這個(gè)?git_repository?類型代表了一個(gè)在內(nèi)存中帶有緩存的指向一個(gè)版本庫(kù)的句柄。 這是最簡(jiǎn)單的方法,只是你必須知道一個(gè)版本庫(kù)的工作目錄或者一個(gè)?.git?文件夾的精確路徑。 另外還有?git_repository_open_ext?,它包括了帶選項(xiàng)的搜索,git_clone?及其同類可以用來(lái)做遠(yuǎn)程版本庫(kù)的本地克隆,?git_repository_init?則可以創(chuàng)建一個(gè)全新的版本庫(kù)。

第二段代碼使用了一種 rev-parse 語(yǔ)法(要了解更多,請(qǐng)看?分支引用?)來(lái)得到 HEAD 真正指向的提交。 返回類型是一個(gè)?git_object?指針,它指代位于版本庫(kù)里的 Git 對(duì)象數(shù)據(jù)庫(kù)中的某個(gè)東西。git_object?實(shí)際上是幾種不同的對(duì)象的 “父” 類型,每個(gè) “子” 類型的內(nèi)存布局和git_object?是一樣的,所以你能安全地把它們轉(zhuǎn)換為正確的類型。 在上面的例子中,git_object_type(commit)?會(huì)返回?GIT_OBJ_COMMIT?,所以轉(zhuǎn)換成?git_commit?指針是安全的。

下一段展示了如何訪問(wèn)一個(gè)提交的詳情。 最后一行使用了?git_oid?類型,這是 Libgit2 用來(lái)表示一個(gè) SHA-1 哈希的方法。

從這個(gè)例子中,我們可以看到一些模式:

  • 如果你聲明了一個(gè)指針,并在一個(gè) Libgit2 調(diào)用中傳遞一個(gè)引用,那么這個(gè)調(diào)用可能返回一個(gè) int 類型的錯(cuò)誤碼。 值?0?表示成功,比它小的則是一個(gè)錯(cuò)誤。

  • 如果 Libgit2 為你填入一個(gè)指針,那么你有責(zé)任釋放它。

  • 如果 Libgit2 在一個(gè)調(diào)用中返回一個(gè)?const?指針,你不需要釋放它,但是當(dāng)它所指向的對(duì)象被釋放時(shí)它將不可用。

  • 用 C 來(lái)寫(xiě)有點(diǎn)蛋疼。

最后一點(diǎn)意味著你應(yīng)該不會(huì)在使用 Libgit2 時(shí)編寫(xiě) C 語(yǔ)言程序。 但幸運(yùn)的是,有許多可用的各種語(yǔ)言的綁定,能讓你在特定的語(yǔ)言和環(huán)境中更加容易的操作 Git 版本庫(kù)。 我們來(lái)看一下下面這個(gè)用 Libgit2 的 Ruby 綁定寫(xiě)成的例子,它叫 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

你可以發(fā)現(xiàn),代碼看起來(lái)更加清晰了。 首先, Rugged 使用異常機(jī)制,它可以拋出類似于ConfigError?或者?ObjectError?之類的東西來(lái)告知錯(cuò)誤的情況。 其次,不需要明確資源釋放,因?yàn)?Ruby 是支持垃圾回收的。 我們來(lái)看一個(gè)稍微復(fù)雜一點(diǎn)的例子:從頭開(kāi)始制作一個(gè)提交。

blob_id = repo.write("Blob contents", :blob) 

index = repo.index
index.read_tree(repo.head.target.tree)
index.add(:path => 'newfile.txt', :oid => blob_id) 

sig = {
    :email => "bob@example.com",
    :name => "Bob User",
    :time => Time.now,
}

commit_id = Rugged::Commit.create(repo,
    :tree => index.write_tree(repo), 
    :author => sig,
    :committer => sig, 
    :message => "Add newfile.txt", 
    :parents => repo.empty? ? [] : [ repo.head.target ].compact, 
    :update_ref => 'HEAD', 
)
commit = repo.lookup(commit_id) 

創(chuàng)建一個(gè)新的 blob ,它包含了一個(gè)新文件的內(nèi)容。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)