A2.3 JGit

2018-02-24 15:23 更新

JGit

如果你想在一個 Java 程序中使用 Git ,有一個功能齊全的 Git 庫,那就是 JGit 。 JGit 是一個用 Java 寫成的功能相對健全的 Git 的實現(xiàn),它在 Java 社區(qū)中被廣泛使用。 JGit 項目由 Eclipse 維護,它的主頁在??。

起步

有很多種方式可以讓 JGit 連接你的項目,并依靠它去寫代碼。 最簡單的方式也許就是使用 Maven 。你可以通過在你的 pom.xml 文件里的?<dependencies>?標簽中增加像下面這樣的片段來完成這個整合。

<dependency>
    <groupId>org.eclipse.jgit</groupId>
    <artifactId>org.eclipse.jgit</artifactId>
    <version>3.5.0.201409260305-r</version>
</dependency>

在你讀到這段文字時?version?很可能已經(jīng)更新了,所以請瀏覽?以獲取最新的倉庫信息。 當這一步完成之后, Maven 就會自動獲取并使用你所需要的 JGit 庫。

如果你想自己管理二進制的依賴包,那么你可以從??獲得預構(gòu)建的 JGit 二進制文件。 你可以像下面這樣執(zhí)行一個命令來將它們構(gòu)建進你的項目。

javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java

底層命令

JGit 的 API 有兩種基本的層次:底層命令和高層命令。 這個兩個術(shù)語都來自 Git ,并且 JGit 也被按照相同的方式粗略地劃分:高層 API 是一個面向普通用戶級別功能的友好的前端(一系列普通用戶使用 Git 命令行工具時可能用到的東西),底層 API 則直接作用于低級的倉庫對象。

大多數(shù) JGit 會話會以?Repository?類作為起點,你首先要做的事就是創(chuàng)建一個它的實例。 對于一個基于文件系統(tǒng)的倉庫來說(嗯, JGit 允許其它的存儲模型),用?FileRepositoryBuilder完成它。

// 創(chuàng)建一個新倉庫
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
    new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create();

// 打開一個存在的倉庫
Repository existingRepo = new FileRepositoryBuilder()
    .setGitDir(new File("my_repo/.git"))
    .build();

無論你的程序是否知道倉庫的確切位置,builder 中的那個流暢的 API 都可以提供給它尋找倉庫所需所有信息。 它可以使用環(huán)境變量 (.readEnvironment()) ,從工作目錄的某處開始并搜索 (.setWorkTree(…).findGitDir()) , 或者僅僅只是像上面那樣打開一個已知的?.git?目錄。

當你擁有一個?Repository?實例后,你就能對它做各種各樣的事。 下面是一個速覽:

// 獲取引用
Ref master = repo.getRef("master");

// 獲取該引用所指向的對象
ObjectId masterTip = master.getObjectId();

// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");

// 裝載對象原始內(nèi)容
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out);

// 創(chuàng)建分支
RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update();

// 刪除分支
RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete();

// 配置
Config cfg = repo.getConfig();
String name = cfg.getString("user", null, "name");

這里完成了一大堆事情,所以我們還是一次理解一段的好。

第一行獲取一個指向?master?引用的指針。 JGit 自動抓取位于?refs/heads/master?的?真正的?master 引用,并返回一個允許你獲取該引用的信息的對象。 你可以獲取它的名字 (.getName()) ,或者一個直接引用的目標對象 (.getObjectId()) ,或者一個指向該引用的符號指針 (.getTarget()) 。 引用對象也經(jīng)常被用來表示標簽的引用和對象,所以你可以詢問某個標簽是否被 “削除” 了,或者說它指向一個標簽對象的(也許很長的)字符串的最終目標。

第二行獲得以?master?引用的目標,它返回一個 ObjectId 實例。 不管是否存在于一個 Git 對象的數(shù)據(jù)庫,ObjectId 都會代表一個對象的 SHA-1 哈希。 第三行與此相似,但是它展示了 JGit 如何處理 rev-parse 語法(要了解更多,請看?分支引用?),你可以傳入任何 Git 了解的對象說明符,然后 JGit 會返回該對象的一個有效的 ObjectId ,或者?null?。

接下來兩行展示了如何裝載一個對象的原始內(nèi)容。 在這個例子中,我們調(diào)用ObjectLoader.copyTo()?直接向標準輸出流輸出對象的內(nèi)容,除此之外 ObjectLoader 還帶有讀取對象的類型和長度并將它以字節(jié)數(shù)組返回的方法。 對于一個(?.isLarge()?返回?true的)大的對象,你可以調(diào)用?.openStream()?來獲得一個類似 InputStream 的對象,它可以在沒有一次性將所有數(shù)據(jù)拉到內(nèi)存的前提下讀取對象的原始數(shù)據(jù)。

接下來幾行展現(xiàn)了如何創(chuàng)建一個新的分支。 我們創(chuàng)建一個 RefUpdate 實例,配置一些參數(shù),然后調(diào)用?.update()?來確認這個更改。 刪除相同分支的代碼就在這行下面。 記住必須先.setForceUpdate(true)?才能讓它工作,否則調(diào)用?.delete()?只會返回?REJECTED?,然后什么都沒有發(fā)生。

最后一個例子展示了如何從 Git 配置文件中獲取?user.name?的值。 這個 Config 實例使用我們先前打開的倉庫做本地配置,但是它也會自動地檢測并讀取全局和系統(tǒng)的配置文件。

這只是底層 API 的冰山一角,另外還有許多可以使用的方法和類。 還有一個沒有放在這里說明的,就是 JGit 是用異常機制來處理錯誤的。 JGit API 有時使用標準的 Java 異常(例如IOException?),但是它也提供了大量 JGit 自己定義的異常類型(例如NoRemoteRepositoryException、?CorruptObjectException?和NoMergeBaseException)。

高層命令

底層 API 更加完善,但是有時將它們串起來以實現(xiàn)普通的目的非常困難,例如將一個文件添加到索引,或者創(chuàng)建一個新的提交。 為了解決這個問題, JGit 提供了一系列高層 API ,使用這些 API 的入口點就是?Git?類:

Repository repo;
// 構(gòu)建倉庫。。。
Git git = new Git(repo);

Git 類有一系列非常好的?構(gòu)建器?風格的高層方法,它可以用來構(gòu)造一些復雜的行為。 我們來看一個例子——做一件類似?git ls-remote?的事。

CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd");
Collection<Ref> remoteRefs = git.lsRemote()
    .setCredentialsProvider(cp)
    .setRemote("origin")
    .setTags(true)
    .setHeads(false)
    .call();
for (Ref ref : remoteRefs) {
    System.out.println(ref.getName() + " -> " + ref.getObjectId().name());

這是一個 Git 類的公共樣式,這個方法返回一個可以讓你串連若干方法調(diào)用來設(shè)置參數(shù)的命令對象,當你調(diào)用?.call()?時它們就會被執(zhí)行。 在這情況下,我們只是請求了?origin?遠程的標簽,而不是頭部。 還要注意用于驗證的?CredentialsProvider?對象的使用。

在 Git 類中還可以使用許多其它的命令,包括但不限于addblame、commit、cleanpush、rebase、revert?和?reset

拓展閱讀

這只是 JGit 的全部能力的冰山一角。 如果你對這有興趣并且想深入學習,在下面可以找到一些信息和靈感。

  • JGit API 在線官方文檔:??。 這是基本的 Javadoc ,所以你也可以在你最喜歡的 JVM IDE 上將它們安裝它們到本地。

  • JGit Cookbook :??擁有許多如何利用 JGit 實現(xiàn)特定任務(wù)的例子。

  • ?指出了幾個好的資源。
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號