-
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.3 附录 B: 将 Git 嵌入你的应用程序 - JGit
JGit
如果你想在 Java 程序中使用 Git,有一个名为 JGit 的功能齐全的 Git 库。JGit 是一个功能相当齐全的 Git 实现,用 Java 本地编写,在 Java 社区中被广泛使用。JGit 项目属于 Eclipse 旗下,其主页位于 https://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
可能会更新;请查看 https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit 获取更新的仓库信息。完成此步骤后,Maven 将自动获取并使用你所需的 JGit 库。
如果你想自己管理二进制依赖项,可以从 https://www.eclipse.org/jgit/download 获取预编译的 JGit 二进制文件。你可以通过运行以下命令将它们构建到你的项目中
javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java
java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App
底层
JGit 有两个基本的 API 级别:底层和外层。这些术语来自 Git 本身,JGit 也大致分为相同类型的区域:外层 API 是常用用户级操作的友好前端(普通用户使用 Git 命令行工具会做的事情),而底层 API 则用于直接与底层仓库对象交互。
大多数 JGit 会话的起点是 Repository
类,你需要做的第一件事是创建它的实例。对于基于文件系统的仓库(是的,JGit 允许其他存储模型),这可以通过使用 FileRepositoryBuilder
来完成
// Create a new repository
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create();
// Open an existing repository
Repository existingRepo = new FileRepositoryBuilder()
.setGitDir(new File("my_repo/.git"))
.build();
构建器有一个流畅的 API,用于提供它需要查找 Git 仓库的所有内容,无论你的程序是否知道它的确切位置。它可以使用环境变量 (.readEnvironment()
),从工作目录中的某个地方开始搜索 (.setWorkTree(…).findGitDir()
),或者只打开上面提到的已知 .git
目录。
获得 Repository
实例后,你可以对它执行各种操作。以下是一些示例
// Get a reference
Ref master = repo.getRef("master");
// Get the object the reference points to
ObjectId masterTip = master.getObjectId();
// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");
// Load raw object contents
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out);
// Create a branch
RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update();
// Delete a branch
RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete();
// Config
Config cfg = repo.getConfig();
String name = cfg.getString("user", null, "name");
这里有很多内容,让我们逐节分析。
第一行获取指向 master
引用 (reference) 的指针。JGit 会自动获取实际的 master
ref,它位于 refs/heads/master
,并返回一个对象,让你可以获取有关该引用的信息。你可以获取其名称 (.getName()
),以及直接引用目标对象 (.getObjectId()
) 或符号引用指向的引用 (.getTarget()
)。Ref 对象还用于表示标签引用和对象,因此你可以询问该标签是否已“剥离”,这意味着它指向(可能很长)标签对象字符串的最终目标。
第二行获取master
引用的目标,该目标作为ObjectId实例返回。ObjectId表示对象的SHA-1哈希值,该哈希值可能存在也可能不存在于Git的对象数据库中。第三行类似,但展示了JGit如何处理rev-parse语法(有关详细信息,请参阅分支引用);您可以传递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;
// construct 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文档可以在https://www.eclipse.org/jgit/documentation找到。这些是标准的Javadoc,因此您最喜欢的JVM IDE也可以在本地安装它们。
-
JGit Cookbook位于https://github.com/centic9/jgit-cookbook,其中包含许多使用JGit执行特定任务的示例。