一篇文章讲明白JGit学习

简介: 一篇文章讲明白JGit学习

参考:

java 使用jgit 操作 git

如果你想在一个 Java 程序中使用 Git ,有一个功能齐全的 Git 库,那就是 JGit 。 JGit 是一个用 Java 写成的功能相对健全的 Git 的实现,它在 Java 社区中被广泛使用。 JGit 项目由 Eclipse 维护,它的主页在 。

1、在本地文件夹建立起与远程仓库的连接

2、根据主干master新建分支并同步到远程

3、提交commit文件到远程

4、从远程拉去代码到本地文件夹

maven依赖

org.eclipse.jgit

org.eclipse.jgit

3.7.0.201502260915-r

public class GitUtilClass {

public static String localRepoPath = "D:/repo";

public static String localRepoGitConfig = "D:/repo/.git";

public static String remoteRepoURI = "git@gitlab.com:wilson/test.git";

public static String localCodeDir = "D:/platplat";

/

新建一个分支并同步到远程仓库

@param branchName

@throws IOException

@throws GitAPIException

/

public static String newBranch(String branchName){

String newBranchIndex = "refs/heads/"+branchName;

String gitPathURI = "";

Git git;

try {

//检查新建的分支是否已经存在,如果存在则将已存在的分支强制删除并新建一个分支

List refs = git.branchList().call();

for (Ref ref : refs) {

if (ref.getName().equals(newBranchIndex)) {

System.out.println("Removing branch before");

git.branchDelete().setBranchNames(branchName).setForce(true)

.call();

break;

}

}

//新建分支

Ref ref = git.branchCreate().setName(branchName).call();

//推送到远程

git.push().add(ref).call();

gitPathURI = remoteRepoURI + " " + "feature/" + branchName;

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (GitAPIException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return gitPathURI;

}

public static void commitFiles() throws IOException, GitAPIException{

String filePath = "";

Git git = Git.open( new File(localRepoGitConfig) );

//创建用户文件的过程

File myfile = new File(filePath);

myfile.createNewFile();

git.add().addFilepattern("pets").call();

//提交

git.commit().setMessage("Added pets").call();

//推送到远程

git.push().call();

}

public static boolean pullBranchToLocal(String cloneURL){

boolean resultFlag = false;

String【】 splitURL = cloneURL.split(" ");

String branchName = splitURL【1】;

String fileDir = localCodeDir+"/"+branchName;

//检查目标文件夹是否存在

File file = new File(fileDir);

if(file.exists()){

deleteFolder(file);

}

Git git;

try {

git = Git.open( new File(localRepoGitConfig) );

git.cloneRepository().setURI(cloneURL).setDirectory(file).call();

resultFlag = true;

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (GitAPIException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return resultFlag;

}

public static void deleteFolder(File file){

if(file.isFile() || file.list().length==0){

file.delete();

}else{

File【】 files = file.listFiles();

for(int i=0;i

deleteFolder(files【i】);

files【i】.delete();

}

}

}

public static void setupRepo() throws GitAPIException{

//建立与远程仓库的联系,仅需要执行一次

Git git = Git.cloneRepository().setURI(remoteRepoURI).setDirectory(new File(localRepoPath)).call();

}

JGit 使用说明

初步

jdk 1.8

第一次我们需要clone这个git,这个git就是我们的schema集。

Git git=Git.cloneRepository()

.setURI("git号")

.setDirectory(new File("gitProject"))

.call();

这样的话,这个git工程就被clone到了我们指定的目录。

3. 当然第二次我们不能再clone了,我们只需要打开上次的git工程就可以进行操作。

Git git=Git.open(new File("gitProject"));

当我们新增或是修改一个文件的时候:

DirCache index=git.add().addFilepattern("schemas/test.md").call();

RevCommit commit=git.commit().setMessage("addFile").call();

git.push().call();

这个新增的文件需要位于我们拉下来的那个git工程里面。

查看一个文件所有的版本(也就是提交记录):在git的命令行中,我们是通过git log 或是git log –filename来实现。这个通过API的实现方式如下:

git.log().addPath(dir/filename.txt).setMaxCount(num).call();

setMaxCount可以指定返回最近num个版本,addPath则是指定查看文件.返回的是Iterable,我们可以通过其迭代器对其进行遍历。我们需要的是得到每一次变更的时间,message,提交的内部识别码,提交人

Iterable iterable=git.log().call();

Iterator iter=iterable.iterator();

while (iter.hasNext()){

RevCommit commit=iter.next();

String email=commit.getAuthorIdent().getEmailAddress();

String name=commit.getAuthorIdent().getName(); //作者

String commitEmail=commit.getCommitterIdent().getEmailAddress();//提交者

String commitName=commit.getCommitterIdent().getName();

int time=commit.getCommitTime();

String fullMessage=commit.getFullMessage();

String shortMessage=commit.getShortMessage(); //返回message的firstLine

String commitID=commit.getName(); //这个应该就是提交的版本号

System.out.println("authorEmail:"+email);

System.out.println("authorName:"+name);

System.out.println("commitEmail:"+commitEmail);

System.out.println("commitName:"+commitName);

System.out.println("time:"+time);

System.out.println("fullMessage:"+fullMessage);

System.out.println("shortMessage:"+shortMessage);

System.out.println("commitID:"+commitID);

}

结果:这个log我们并没有指定哪一个文件,也没有指定返回多少个,我们可以如前面提到那样指定文件,指定返回个数,但是从结果中我们确实得到我们想要的东西

authorEmail:yulin@DESKTOP-ALAIMHD

authorName:yulin

commitEmail:yulin@DESKTOP-ALAIMHD

commitName:yulin

time:1515468403

fullMessage:addFile

shortMessage:addFile

commitID:d22491b948e8013df552549a753dcafd4d9b3c4b

authorEmail:

authorName:

commitEmail:

commitName:*

time:1515463064

fullMessage:【添加】gitignore文件

shortMessage:【添加】gitignore文件

commitID:be1be26068cd4fb5653c6efd3299f465d5863234

注意这里有这样一个问题,如果你使用了.addPath(dir/filename.txt),也就是你只想得到某个文件的提交。这种方式的确可以实现,如果某一次的提交,包含了多个文件,其中包含了这个文件,该次提交也会被包含到结果其中。(其实这个还是可以理解的。)

我们得到指定文件的所有版本后,需要去取得每一个版本的变化,这样我们才能显示出每一个版本不同的内容。git命令可以用diff实现,那么在JGit中的调用呢.

如我们比较一个特定文件最近两次的提交内容的不同。那么我们首先需要得到最近两次的commit。然后根据commit得到变化内容。如下:

Git git=Git.open(new File("gitProject"));

Repository repository=git.getRepository();

List list=new ArrayList();

Iterable iterable=git.log().addPath("schemas/test1.md").setMaxCount(2).call();

for(RevCommit revCommit:iterable){

list.add(revCommit);

}

if(list.size()==2){

AbstractTreeIterator newCommit=getAbstractTreeIterator(list.get(0),repository);

AbstractTreeIterator oldCommit=getAbstractTreeIterator(list.get(1),repository);

List diff=git.diff().setOldTree(oldCommit).setNewTree(newCommit).call();

ByteArrayOutputStream outputStream=new ByteArrayOutputStream();

DiffFormatter diffFormatter=new DiffFormatter(outputStream);

//设置比较器为忽略空白字符对比(Ignores all whitespace)

diffFormatter.setDiffComparator(RawTextComparator.WS_IGNORE_ALL);

diffFormatter.setRepository(repository); // 这里为什么还要设置它

for(DiffEntry diffEntry:diff){

diffFormatter.format(diffEntry);

System.out.println(outputStream.toString("UTF-8"));

outputStream.reset();

}

}

git.close();

另外需要通过下面这个方法根据commit得到AbstractTreeIterator,如下:

public static AbstractTreeIterator getAbstractTreeIterator(RevCommit commit, Repository repository ){

RevWalk revWalk=new RevWalk(repository);

CanonicalTreeParser treeParser=null;

try {

RevTree revTree=revWalk.parseTree(commit.getTree().getId());

treeParser=new CanonicalTreeParser();

treeParser.reset(repository.newObjectReader(),revTree.getId());

revWalk.dispose();

} catch (IOException e) {

e.printStackTrace();

}

return treeParser;

}

通过以上代码,我们可以得到schemas/test1.md文件两次commit内容的不同,结果如下:

diff --git a/schemas/test.md b/schemas/test.md

index e8fce5c..c226794 100644

--- a/schemas/test.md

+++ b/schemas/test.md

@@ -1,4 +1,4 @@

-# JSON测试效率总结

+# JSON测试效率总结 test4

我们可以看到得到的结果的变化内容已经用 - //代码效果参考:http://www.zidongmutanji.com/bxxx/552108.html

+进行了标注,这与我们平常看到的diff命令结果是相符合的

但是这里就有这样的一个问题,我们虽然通过addPath来得到了某个文件的commit,但是我们得到diff内容是通过commit来的,如果一次commit包含多个文件,那么我们的diff内容自然也会所有更改文件的内容,那么这与我们说的得到某个文件的变化内容就有一定的出入了,但是这是因为我们的一次commit包含多个文件修改导致的。

那么我们能否对DiffEntry的内容进行筛选呢?通过前面的代码我们看到事实上我们的变化内容是通过DiffEntry来得到的,如果一次提交内容包含了多个文件的改变,那么我们也会得到对应数目的DiffEntry,我们需要对DiffEntry进行筛选,从而挑选出对应特定文件的DiffEntry,从而得到特定文件的变化内容,接下来试一试。

筛选DiffEntry

发现DiffEntry中有oldPath,newPath这样的属性。

/ File name of the old (pre-image). /

protected String oldPath;

/** File name of the new (post-image). /

protected String newPath;

那么如果我们得到了文件名,那就就可以根据文件名进行筛选了,如下:

for(DiffEntry diffEntry:diff){

diffFormatter.format(diffEntry);

System.out.println("new Path:"+diffEntry.getNewPath());

System.out.println("old path:"+diffEntry.getOldPath());

System.out.println(outputStream.toString("UTF-8"));

outputStream.reset();

}

结果:确实我们得到了文件名

new Path:schemas/test.md

old path:schemas/test.md

diff --git a/schemas/test.md b/schemas/test.md

index e8fce5c..c226794 100644

--- a/schemas/test.md

+++ b/schemas/test.md

@@ -1,4 +1,4 @@

-# JSON测试效率总结

+# JSON测试效率总结 test4

通过前面我们基本可以得到制指定文件版本之间的差异内容,接下来我们去获取指定文件指定版本的文件内容,以下为示例代码:

public static ByteArrayOutputStream read(String revision, Git git) {

ByteArrayOutputStream out = new ByteArrayOutputStream();

Repository repository = null;

try {

//gitDir表示git库目录

// Git git = Git.open(new File("gitProject"));

repository = git.getRepository();

RevWalk walk = new RevWalk(repository);

ObjectId objId = repository.resolve(revision);

RevCommit revCommit = walk.parseCommit(objId);

RevTree revTree = revCommit.getTree();

//child表示相对git库的文件路径

TreeWalk treeWalk = TreeWalk.forPath(repository, "schemas/test.md", revTree);

ObjectId blobId = treeWalk.getObjectId(0);

ObjectLoader loader = repository.open(blobId);

loader.copyTo(out);

} catch (IOException e) {

e.printStackTrace();

} catch (JGitInternalException e) {

e.printStackTrace();

} finally {

if (repository != null)

repository.close();

}

return out;

}

//调用

ByteArrayOutputStream outputStream=read("f532e63bac93f05345da1ff665687e69df9732dc",git);

System.out.println(outputStream.toString("UTF-8"));

我们仍然是通过commitID去获取,不过这里是直接给出了CommitID,我们同样可以像前面的代码那样先获取commit,结果我们确实拿到了这个版本文件的全部内容。(结果太多就不进行展示了)

JGit常用功能(提交、回滚、日志查询)

public class GitUtil {

private final static String GIT = ".git";

private final static String REF_REMOTES = "refs/remotes/origin/";

/*

将文件列表提交到git仓库中

@param gitRoot git仓库目录

@param files 需要提交的文件列表

@param remark 备注

@return 返回本次提交的版本号

@throws IOException

/

public static String commitToGitRepository(String gitRoot, List files, String remark)

throws Exception {

if (StringUtils.isNotBlank(gitRoot) files != null files.size() > 0) {

File rootDir = new File(gitRoot);

//初始化git仓库

if (new File(gitRoot + File.separator + GIT).exists() == false) {

Git.init().setDirectory(rootDir).call();

}

//打开git仓库

Git git = Git.open(rootDir);

//判断工作区与暂存区的文件内容是否有变更

List diffEntries = git.diff()

.setPathFilter(PathFilterGroup.createFromStrings(files))

.setShowNameAndStatusOnly(true).call();

if (diffEntries == null || diffEntries.size() == 0) {

throw new Exception("提交的文件内容都没有被修改,不能提交");

}

//被修改过的文件

List updateFiles = new ArrayList();

ChangeType changeType;

for (DiffEntry entry : diffEntries) {

changeType = entry.getChangeType();

switch (changeType) {

case ADD:

case COPY:

case RENAME:

case MODIFY:

updateFiles.add(entry.

相关文章
|
7月前
|
监控 Java API
Spring WebFlux 响应式编程技术详解与实践指南
本文档全面介绍 Spring WebFlux 响应式编程框架的核心概念、架构设计和实际应用。作为 Spring 5 引入的革命性特性,WebFlux 提供了完全的响应式、非阻塞的 Web 开发栈,能够显著提升系统的并发处理能力和资源利用率。本文将深入探讨 Reactor 编程模型、响应式流规范、WebFlux 核心组件以及在实际项目中的最佳实践,帮助开发者构建高性能的响应式应用系统。
1188 0
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
5月前
|
Linux
CentOS 7 安装 unzip-6.0-21.el7.x86_64.rpm 步骤详解(附安装包)
本文详解在CentOS 7上安装unzip-6.0-21.el7.x86_64.rpm的两种方法:使用yum自动安装或rpm命令手动安装,附下载链接与详细步骤,助你快速配置解压工具。
1392 0
|
前端开发 API 网络架构
深入浅出:GraphQL 的优势与使用场景
【10月更文挑战第6天】深入浅出:GraphQL 的优势与使用场景
1484 0
|
JavaScript
基于Vue2.X/Vue3.X对Monaco Editor在线代码编辑器进行封装与使用
这篇文章介绍了如何在Vue 2.X和Vue 3.X项目中封装和使用Monaco Editor在线代码编辑器,包括安装所需依赖、创建封装组件、在父组件中调用以及处理Vue 3中可能遇到的问题。
3778 1
基于Vue2.X/Vue3.X对Monaco Editor在线代码编辑器进行封装与使用
|
人工智能 前端开发 Java
用git rebase命令合并开发阶段中多条commit提交记录
通过 `git rebase`,可以合并多个提交记录,使开发历史更简洁清晰。操作分为 6 步:查看提交历史 (`git log --oneline`)、设置需合并的提交数 (`git rebase -i HEAD~N`)、修改动作标识为 `s`(squash)、保存退出编辑、调整提交信息、强制推送至远程仓库 (`git push -f`)。此方法适合清理本地无关提交,但若有团队协作或冲突风险,需谨慎使用以避免问题。
2216 60
|
SQL Java 数据库连接
mybatisplus QueryWrapper or写法
# MyBatis-Plus QueryWrapper的OR写法详解 MyBatis-Plus是一款基于MyBatis的增强工具,提供了丰富的简化操作,使开发者能更高效地进行数据库操作。`QueryWrapper`是MyBatis-Plus中用于构建查询条件的一个核心类,支持多种条件组合,包括AND和OR条件。本文将详细介绍如何使用 `QueryWrapper`实现OR条件的查询。 ## QueryWrapper简介 `QueryWrapper`用于构建动态SQL查询条件,它封装了各种条件构造方法,使得查询条件的构建更加简洁和直观。`QueryWrapper`中提供了丰富的方法来支持多
2686 0
|
IDE 开发工具
【开发IDE升级】如何对IDEA版本进行升级
本文介绍了如何将 IntelliJ IDEA Ultimate 从 2020.2.2 版本升级到 2022.3.2 版本。主要内容包括准备工作、卸载旧版本和安装新版本的步骤。首先,从官网下载所需版本并备份旧版配置;接着,通过 Uninstall.exe 卸载旧版,保留配置和插件;最后,安装新版并完成激活。详细的操作步骤和截图帮助用户顺利完成升级过程。
16467 1
【开发IDE升级】如何对IDEA版本进行升级
|
算法 Java UED
你的Spring Boot应用是否足够健壮?揭秘限流功能的实现秘诀
【8月更文挑战第29天】限流是保障服务稳定性的关键策略,通过限制单位时间内的请求数量防止服务过载。本文基于理论介绍,结合Spring Boot应用实例,展示了使用`@RateLimiter`注解和集成`Resilience4j`库实现限流的方法。无论采用哪种方式,都能有效控制请求速率,增强应用的健壮性和用户体验。通过这些示例,读者可以灵活选择适合自身需求的限流方案。
690 2
|
NoSQL 安全 Java
解决Unknown redis exception及event executor terminated错误的方法
解决这类问题时,保持耐心和细致是关键。通常,通过系统地检查和排除潜在原因,大多数问题最终都能被解决。
2515 1