Q1-java 程序如何访问 git 的各种信息?比如分支信息,分支差异,提交记录等等

Java程序可以使用Git客户端库(如JGit)来访问Git的各种信息。

这些库提供了Java API,使得Java程序可以直接与Git进行交互和查询。

下面是一些常见的Git信息访问操作示例:

  1. 访问分支信息:
    • 获取所有分支:使用 Git.branchList() 方法可以获取所有分支的列表。
    • 获取当前分支:使用 Git.getRepository().getBranch() 方法可以获取当前所在的分支。
    • 创建新分支:使用 Git.branchCreate().setName("branch_name").call() 方法可以创建一个新分支。
  2. 访问提交记录:
    • 获取提交记录:使用 Git.log().all().call() 方法可以获取所有提交记录的列表。
    • 获取某个分支的提交记录:使用 Git.log().add(git.getRepository().resolve("branch_name")).call() 方法可以获取特定分支的提交记录。
    • 获取某个提交的详细信息:使用 Git.show().setObjectId(commitId).call() 方法可以获取特定提交的详细信息。
  3. 访问分支差异:
    • 获取两个分支之间的差异:使用 Git.diff().setOldTree(oldTree).setNewTree(newTree).call() 方法可以获取两个分支之间的差异。
    • 获取某个提交与其父提交之间的差异:使用 Git.diff().setOldTree(parentCommit).setNewTree(commit).call() 方法可以获取某个提交与其父提交之间的差异。

这些只是一些常见的操作示例,实际上,Git客户端库(如JGit)提供了更多的API和方法来访问Git的各种信息。具体的使用方法可以参考相应的Git客户端库的文档和示例代码。

Q2-可以访问 git 的开源库

Java可以使用以下开源工具库来访问Git信息:

  1. JGit:JGit是一个纯Java实现的Git客户端库,由Eclipse项目提供。它提供了Java API来与Git进行交互和查询,包括访问分支、提交记录、差异等功能。

  2. GitPython:GitPython是一个用于访问Git仓库的Python库,它提供了Python API来操作和查询Git信息。Java程序可以通过使用Jython或通过与Python交互的方式来使用GitPython库。

  3. LibGit2:LibGit2是一个用C语言编写的跨平台Git客户端库,它提供了多种语言的绑定,包括Java。通过使用LibGit2的Java绑定,可以在Java程序中访问Git仓库的信息。

Q3-一些工具插件

不,除了JGit之外,还有其他Java API可以用于访问Git信息。

以下是一些常见的Java API和工具库:

  1. Gitblit: Gitblit是一个基于Java的Git服务器,它提供了RESTful API和Java API来管理和访问Git仓库。它可以用作独立的Git服务器,也可以嵌入到其他Java应用程序中。

  2. Apache GitBox: Apache GitBox是Apache软件基金会提供的Git托管服务,它提供了Java API来访问和管理Git仓库。它使用了JGit作为底层实现。

  3. EGit: EGit是Eclipse项目提供的Git插件,它提供了Java API来访问和操作Git仓库。它是基于JGit的,可以与Eclipse集成使用。

  4. SourceTree API: SourceTree是一款流行的Git客户端,它提供了Java API来访问Git仓库的信息和操作。它可以用于自动化Git流程的集成。

这些工具库提供了不同的功能和集成选项,可以根据项目需求选择适合的工具库。

jgit 入门例子

maven

  [xml]
1
2
3
4
5
<dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> <version>5.11.0.202103091610-r</version> </dependency>

例子

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package org.example; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryBuilder; import org.eclipse.jgit.revwalk.RevCommit; import java.io.File; import java.io.IOException; import java.util.List; public class JGitExample { public static void main(String[] args) { try { // 打开现有的Git仓库 Repository repository = new RepositoryBuilder() .setGitDir(new File("D:\\code\\github\\jgit-learn/.git")) .build(); // 创建Git对象 Git git = new Git(repository); // 获取所有分支 List<Ref> branches = git.branchList().call(); for (Ref branch : branches) { System.out.println("Branch: " + branch.getName()); } // 获取最新的提交记录 Iterable<RevCommit> commits = git.log().setMaxCount(10).call(); for (RevCommit commit : commits) { System.out.println("Commit: " + commit.getName()); System.out.println("Author: " + commit.getAuthorIdent().getName()); System.out.println("Message: " + commit.getFullMessage()); System.out.println("-----------------------"); } // 创建新分支 Ref newBranch = git.branchCreate().setName("new-branch").call(); System.out.println("New branch created: " + newBranch.getName()); // 关闭Git对象和仓库 git.close(); repository.close(); } catch (IOException | GitAPIException e) { e.printStackTrace(); } } }

日志如下:

  [plaintext]
1
2
3
4
5
6
7
Branch: refs/heads/master Commit: c17645337ed4b158a6269e76412a76d1d4679bb6 Author: d Message: Initial commit ----------------------- New branch created: refs/heads/new-branch

可以看到分支的信息。

也可以创建分支。

git 分支差异对比

代码

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package org.example; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryBuilder; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import java.io.File; import java.io.IOException; import java.util.List; public class JGitDifferExample { public static void main(String[] args) { try { // 打开现有的Git仓库 Repository repository = new RepositoryBuilder() .setGitDir(new File("D:\\code\\github\\jgit-learn/.git")) .build(); // 创建Git对象 Git git = new Git(repository); // 比较两个分支的差异 List<DiffEntry> diffs = git.diff() .setOldTree(prepareTreeParser(git, repository, "refs/heads/release_1.0.0")) .setNewTree(prepareTreeParser(git,repository, "refs/heads/master")) .call(); // 打印差异 for (DiffEntry diff : diffs) { System.out.println("Diff: " + diff.getChangeType() + ", old: " + diff.getOldPath() + ", new: " + diff.getNewPath()); } // 关闭Git对象和仓库 git.close(); repository.close(); } catch (IOException | GitAPIException e) { e.printStackTrace(); } } private static AbstractTreeIterator prepareTreeParser(Git git, Repository repository, String branch) throws IOException { Ref head = getRefByName(git, branch); RevWalk walk = new RevWalk(repository); RevCommit commit = walk.parseCommit(head.getObjectId()); RevTree tree = walk.parseTree(commit.getTree().getId()); CanonicalTreeParser treeParser = new CanonicalTreeParser(); try (ObjectReader reader = repository.newObjectReader()) { treeParser.reset(reader, tree.getId()); } walk.dispose(); return treeParser; } private static Ref getRefByName(Git git, String branchName) { try { // 获取所有分支 List<Ref> branches = git.branchList().call(); for (Ref branch : branches) { // System.out.println("Branch: " + branch.getName()); if(branch.getName().equals(branchName)) { return branch; } } return null; } catch (GitAPIException e) { throw new RuntimeException(e); } } }

日志

  [plaintext]
1
2
Diff: DELETE, old: src/main/java/org/example/JGitDifferExample.java, new: /dev/null Diff: MODIFY, old: src/main/java/org/example/Main.java, new: src/main/java/org/example/Main.java

可以看到差异的类别,文件信息。

git 差异精确到行

说明

如果是编辑,可以精确到具体的行信息。

这样我们就可以知道具体变化的行,而不用关心整个文件。

代码

  [java]
1
2
3
4
5
6
7
// 打印差异 for (DiffEntry diff : diffs) { System.out.println("Diff: " + diff.getChangeType() + ", old: " + diff.getOldPath() + ", new: " + diff.getNewPath()); outputModifyByLine(diff, repository); }

对应的行变化内容:

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static void outputModifyByLine(DiffEntry diff, Repository repository) { try { if (diff.getChangeType() == DiffEntry.ChangeType.MODIFY) { // 获取变更的具体行号 DiffFormatter formatter = new DiffFormatter(DisabledOutputStream.INSTANCE); formatter.setRepository(repository); FileHeader fileHeader = formatter.toFileHeader(diff); for (HunkHeader hunkHeader : fileHeader.getHunks()) { for (Edit edit : hunkHeader.toEditList()) { if (edit.getType() != Edit.Type.DELETE) { System.out.println("Line range: " + (edit.getBeginA() + 1) + " - " + (edit.getEndA() + 1)); } } } } } catch (IOException e) { throw new RuntimeException(e); } }

对应的结果:

  [plaintext]
1
2
3
Diff: DELETE, old: src/main/java/org/example/JGitDifferExample.java, new: /dev/null Diff: MODIFY, old: src/main/java/org/example/Main.java, new: src/main/java/org/example/Main.java Line range: 5 - 6

拓展阅读

jgit-cookbook

基于jacoco,JGit 二次开发增量代码覆盖率工具

参考资料

chat