# JGit
如果你想在一個 Java 程序中使用 Git ,有一個功能齊全的 Git 庫,那就是 JGit 。 JGit 是一個用 Java 寫成的功能相對健全的 Git 的實現,它在 Java 社區中被廣泛使用。 JGit 項目由 Eclipse 維護,它的主頁在?[*http://www.eclipse.org/jgit*](http://www.eclipse.org/jgit)?。
## 起步
有很多種方式可以讓 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`?很可能已經更新了,所以請瀏覽[*http://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit*](http://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit)?以獲取最新的倉庫信息。 當這一步完成之后, Maven 就會自動獲取并使用你所需要的 JGit 庫。
如果你想自己管理二進制的依賴包,那么你可以從?[*http://www.eclipse.org/jgit/download*](http://www.eclipse.org/jgit/download)?獲得預構建的 JGit 二進制文件。 你可以像下面這樣執行一個命令來將它們構建進你的項目。
~~~
javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java
~~~
## 底層命令
JGit 的 API 有兩種基本的層次:底層命令和高層命令。 這個兩個術語都來自 Git ,并且 JGit 也被按照相同的方式粗略地劃分:高層 API 是一個面向普通用戶級別功能的友好的前端(一系列普通用戶使用 Git 命令行工具時可能用到的東西),底層 API 則直接作用于低級的倉庫對象。
大多數 JGit 會話會以?`Repository`?類作為起點,你首先要做的事就是創建一個它的實例。 對于一個基于文件系統的倉庫來說(嗯, JGit 允許其它的存儲模型),用?`FileRepositoryBuilder`完成它。
~~~
// 創建一個新倉庫
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 都可以提供給它尋找倉庫所需所有信息。 它可以使用環境變量 (`.readEnvironment()`) ,從工作目錄的某處開始并搜索 (`.setWorkTree(…).findGitDir()`) , 或者僅僅只是像上面那樣打開一個已知的?`.git`?目錄。
當你擁有一個?`Repository`?實例后,你就能對它做各種各樣的事。 下面是一個速覽:
~~~
// 獲取引用
Ref master = repo.getRef("master");
// 獲取該引用所指向的對象
ObjectId masterTip = master.getObjectId();
// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");
// 裝載對象原始內容
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out);
// 創建分支
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()`) 。 引用對象也經常被用來表示標簽的引用和對象,所以你可以詢問某個標簽是否被 “削除” 了,或者說它指向一個標簽對象的(也許很長的)字符串的最終目標。
第二行獲得以?`master`?引用的目標,它返回一個 ObjectId 實例。 不管是否存在于一個 Git 對象的數據庫,ObjectId 都會代表一個對象的 SHA-1 哈希。 第三行與此相似,但是它展示了 JGit 如何處理 rev-parse 語法(要了解更多,請看?[分支引用](http://git-scm.com/book/zh/v2/1-git-tools/_branch_references)?),你可以傳入任何 Git 了解的對象說明符,然后 JGit 會返回該對象的一個有效的 ObjectId ,或者?`null`?。
接下來兩行展示了如何裝載一個對象的原始內容。 在這個例子中,我們調用`ObjectLoader.copyTo()`?直接向標準輸出流輸出對象的內容,除此之外 ObjectLoader 還帶有讀取對象的類型和長度并將它以字節數組返回的方法。 對于一個(?`.isLarge()`?返回?`true`的)大的對象,你可以調用?`.openStream()`?來獲得一個類似 InputStream 的對象,它可以在沒有一次性將所有數據拉到內存的前提下讀取對象的原始數據。
接下來幾行展現了如何創建一個新的分支。 我們創建一個 RefUpdate 實例,配置一些參數,然后調用?`.update()`?來確認這個更改。 刪除相同分支的代碼就在這行下面。 記住必須先`.setForceUpdate(true)`?才能讓它工作,否則調用?`.delete()`?只會返回?`REJECTED`?,然后什么都沒有發生。
最后一個例子展示了如何從 Git 配置文件中獲取?`user.name`?的值。 這個 Config 實例使用我們先前打開的倉庫做本地配置,但是它也會自動地檢測并讀取全局和系統的配置文件。
這只是底層 API 的冰山一角,另外還有許多可以使用的方法和類。 還有一個沒有放在這里說明的,就是 JGit 是用異常機制來處理錯誤的。 JGit API 有時使用標準的 Java 異常(例如`IOException`?),但是它也提供了大量 JGit 自己定義的異常類型(例如`NoRemoteRepositoryException`、?`CorruptObjectException`?和`NoMergeBaseException`)。
## 高層命令
底層 API 更加完善,但是有時將它們串起來以實現普通的目的非常困難,例如將一個文件添加到索引,或者創建一個新的提交。 為了解決這個問題, JGit 提供了一系列高層 API ,使用這些 API 的入口點就是?`Git`?類:
~~~
Repository repo;
// 構建倉庫。。。
Git git = new Git(repo);
~~~
Git 類有一系列非常好的?*構建器*?風格的高層方法,它可以用來構造一些復雜的行為。 我們來看一個例子——做一件類似?`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 類的公共樣式,這個方法返回一個可以讓你串連若干方法調用來設置參數的命令對象,當你調用?`.call()`?時它們就會被執行。 在這情況下,我們只是請求了?`origin`?遠程的標簽,而不是頭部。 還要注意用于驗證的?`CredentialsProvider`?對象的使用。
在 Git 類中還可以使用許多其它的命令,包括但不限于`add`、`blame`、`commit`、`clean`、`push`、`rebase`、`revert`?和?`reset`。
## 拓展閱讀
這只是 JGit 的全部能力的冰山一角。 如果你對這有興趣并且想深入學習,在下面可以找到一些信息和靈感。
* JGit API 在線官方文檔:?[*http://download.eclipse.org/jgit/docs/latest/apidocs*](http://download.eclipse.org/jgit/docs/latest/apidocs)?。 這是基本的 Javadoc ,所以你也可以在你最喜歡的 JVM IDE 上將它們安裝它們到本地。
* JGit Cookbook :?[*https://github.com/centic9/jgit-cookbook*](https://github.com/centic9/jgit-cookbook)?擁有許多如何利用 JGit 實現特定任務的例子。
* [*http://stackoverflow.com/questions/6861881*](http://stackoverflow.com/questions/6861881)?指出了幾個好的資源。
- 前言
- Scott Chacon 序
- Ben Straub 序
- 獻辭
- 貢獻者
- 引言
- 1. 起步
- 1.1 關于版本控制
- 1.2 Git 簡史
- 1.3 Git 基礎
- 1.4 命令行
- 1.5 安裝 Git
- 1.6 初次運行 Git 前的配置
- 1.7 獲取幫助
- 1.8 總結
- 2. Git 基礎
- 2.1 獲取 Git 倉庫
- 2.2 記錄每次更新到倉庫
- 2.3 查看提交歷史
- 2.4 撤消操作
- 2.5 遠程倉庫的使用
- 2.6 打標簽
- 2.7 Git 別名
- 2.8 總結
- 3. Git 分支
- 3.1 分支簡介
- 3.2 分支的新建與合并
- 3.3 分支管理
- 3.4 分支開發工作流
- 3.5 遠程分支
- 3.6 變基
- 3.7 總結
- 4. 服務器上的 Git
- 4.1 協議
- 4.2 在服務器上搭建 Git
- 4.3 生成 SSH 公鑰
- 4.4 配置服務器
- 4.5 Git 守護進程
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方托管的選擇
- 4.10 總結
- 5. 分布式 Git
- 5.1 分布式工作流程
- 5.2 向一個項目貢獻
- 5.3 維護項目
- 5.4 總結
- 6. GitHub
- 6.1 賬戶的創建和配置
- 6.2 對項目做出貢獻
- 6.3 維護項目
- 6.4 管理組織
- 6.5 腳本 GitHub
- 6.6 總結
- 7. Git 工具
- 7.1 選擇修訂版本
- 7.2 交互式暫存
- 7.3 儲藏與清理
- 7.4 簽署工作
- 7.5 搜索
- 7.6 重寫歷史
- 7.7 重置揭密
- 7.8 高級合并
- 7.9 Rerere
- 7.10 使用 Git 調試
- 7.11 子模塊
- 7.12 打包
- 7.13 替換
- 7.14 憑證存儲
- 7.15 總結
- 8. 自定義 Git
- 8.1 配置 Git
- 8.2 Git 屬性
- 8.3 Git 鉤子
- 8.4 使用強制策略的一個例子
- 8.5 總結
- 9. Git 與其他系統
- 9.1 作為客戶端的 Git
- 9.2 遷移到 Git
- 9.3 總結
- 10. Git 內部原理
- 10.1 底層命令和高層命令
- 10.2 Git 對象
- 10.3 Git 引用
- 10.4 包文件
- 10.5 引用規格
- 10.6 傳輸協議
- 10.7 維護與數據恢復
- 10.8 環境變量
- 10.9 總結
- A. 其它環境中的 Git
- A1.1 圖形界面
- A1.2 Visual Studio 中的 Git
- A1.3 Eclipse 中的 Git
- A1.4 Bash 中的 Git
- A1.5 Zsh 中的 Git
- A1.6 Powershell 中的 Git
- A1.7 總結
- B. 將 Git 嵌入你的應用
- A2.1 命令行 Git 方式
- A2.2 Libgit2
- A2.3 JGit
- C. Git 命令
- A3.1 設置與配置
- A3.2 獲取與創建項目
- A3.3 快照基礎
- A3.4 分支與合并
- A3.5 項目分享與更新
- A3.6 檢查與比較
- A3.7 調試
- A3.8 補丁
- A3.9 郵件
- A3.10 外部系統
- A3.11 管理
- A3.12 底層命令