JGit 的 Java 操作 Git
最编程
2024-03-09 21:23:48
...
Java操作Git之JGit
博文地址:https://www.cnblogs.com/imchentiefeng/articles/java-git-jgit.html
git地址:Java操作Git之JGit.md
背景
最近在做的项目中,有需求需要向git仓库上传文件,于是考虑到了在项目中通过Java代码来操作git仓库,记得以前自己搭建过Gitblit环境,它是一个开源的、基于Java编写的Git服务端,于是下载了Gitblit的源码,看到是基于JGit进行的封装,于是通过查看源码,加上参考JGit API 在线官方文档以及JGit Cookbook,编写了一个供自己使用的工具类,现分享给大家。
开始
1、引入依赖
我这里使用的Maven环境,引入依赖如下:
<!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit -->
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>5.10.0.202012080955-r</version>
</dependency>
2、git分支类型
考虑到仓库分为本地仓库和远端仓库,我创建了一个枚举帮助后面的工具类中使用,如下:
import lombok.Getter;
/**
* git分支类型
*
* @author chentiefeng
* @date 2021/2/10 15:03
*/
@Getter
public enum GitBranchType {
/**
* 本地分支
*/
LOCAL("refs/heads/"),
/**
* 远程分支
*/
REMOTE("refs/remotes/origin/");
/**
* 分支前缀
*/
private String prefix;
GitBranchType(String prefix) {
this.prefix = prefix;
}
}
3、工具类
工具类内容如下:
import com.chen.common.git.enums.GitBranchType;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
/**
* Git工具类
* 更多jgit的操作,请看:
* 官方文档:http://archive.eclipse.org/jgit/site/3.7.0.201502260915-r/index.html
* 示例代码:https://github.com/centic9/jgit-cookbook
* @author chentiefeng
* @date 2021/2/10 14:02
*/
@Slf4j
public class GitUtils {
/**
* 提交文件到仓库 (包括新增的、更改的、删除的)
* @param git
* @param credential
* @param filePattern
* @param commitMessage
* @return
* @throws GitAPIException
* @throws IOException
*/
public static boolean commitFiles(Git git, CredentialsProvider credential, String filePattern, String commitMessage) throws GitAPIException, IOException {
//添加
git.add().addFilepattern(filePattern).call();
git.add().addFilepattern(filePattern).setUpdate(true).call();
//提交
git.commit().setMessage(commitMessage).call();
//推送到远程
Iterable<PushResult> pushResults = git.push().setCredentialsProvider(credential).call();
printCommitPushResult(pushResults, git.getRepository().getBranch(), commitMessage);
return true;
}
/**
* 打印提交文件的日志
* @param results
*/
private static void printCommitPushResult(Iterable<PushResult> results, String branchName, String commitMessage) {
log.info("git add && git commit -m '{}'", commitMessage);
log.info("git push");
for (PushResult result : results) {
RemoteRefUpdate remoteRefUpdate = result.getRemoteUpdate(GitBranchType.LOCAL.getPrefix() + branchName);
if (Status.OK.equals(remoteRefUpdate.getStatus())) {
log.info("remote: " + result.getMessages().substring(0, result.getMessages().length() - 1));
} else {
log.error("remote: " + result.getMessages());
}
log.info("To {}", result.getURI());
}
}
/**
* 删除分支
* @param git
* @param credential
* @param branchName
* @return
* @throws GitAPIException
* @throws IOException
*/
public static boolean removeBranch(Git git, CredentialsProvider credential, String branchName) throws GitAPIException, IOException {
// master分支不能删除
if ("master".equals(branchName)) {
return false;
}
String oldBranch = git.getRepository().getBranch();
//如果要删除的分支等于当前分支,切换到master
if (oldBranch.equals(branchName)) {
git.checkout().setName("master").call();
}
git.branchDelete().setBranchNames(GitBranchType.LOCAL.getPrefix() + branchName).setForce(true).call();
git.branchDelete().setBranchNames(GitBranchType.REMOTE.getPrefix() + branchName).setForce(true).call();
//推送到远程
String branchFullName = GitBranchType.LOCAL.getPrefix() + branchName;
RefSpec refSpec = new RefSpec(":" + branchFullName).setForceUpdate(true);
Iterable<PushResult> results = git.push().setCredentialsProvider(credential).setRefSpecs(refSpec).call();
printRemoveBranchResult(results, branchFullName, branchName);
return true;
}
/**
* 打印删除分支的日志
* @param results
* @param branchFullName
*/
private static void printRemoveBranchResult(Iterable<PushResult> results, String branchFullName, String branchName) {
log.info("git push origin --delete {}", branchName);
for (PushResult result : results) {
RemoteRefUpdate remoteRefUpdate = result.getRemoteUpdate(branchFullName);
if (Status.OK.equals(remoteRefUpdate.getStatus())) {
log.info("remote: " + result.getMessages().substring(0, result.getMessages().length() - 1));
} else {
log.error("remote: " + result.getMessages());
}
log.info("To {}", result.getURI());
log.info("- [deleted] {}", branchName);
}
}
/**
* 创建分支
* @param git
* @param branchName
* @return
* @throws GitAPIException
* @throws IOException
*/
public static String createBranch(Git git, CredentialsProvider credential, String branchName) throws GitAPIException, IOException {
//如果本地存在分支,直接返回
if (getBranches(git, GitBranchType.LOCAL).contains(branchName)) {
return branchName;
}
//如果远端存在分支,则创建本地分支
if (getBranches(git, GitBranchType.REMOTE).contains(branchName)) {
String oldBranch = git.getRepository().getBranch();
git.checkout().setName(branchName).setCreateBranch(true).call();
git.checkout().setName(oldBranch).call();
return branchName;
}
//新建分支
git.branchCreate().setName(branchName).call();
String oldBranch = git.getRepository().getBranch();
git.checkout().setName(branchName).call();
//推送到远程
git.push().setCredentialsProvider(credential).call();
git.checkout().setName(oldBranch).call();
return branchName;
}
/**
* 获取所有分支
* @param git
* @param branchType 分支类型,分为本地分支和远程分支
* @return
* @throws GitAPIException
* @throws IOException
*/
public static List<String> getBranches(Git git, GitBranchType branchType) throws GitAPIException, IOException {
if (GitBranchType.LOCAL.equals(branchType)) {
List<Ref> refs = git.branchList().call();
return refs.stream().map(ref -> ref.getName().substring(GitBranchType.LOCAL.getPrefix().length()))
.collect(Collectors.toList());
} else {
List<Ref> refs = git.getRepository().getRefDatabase().getRefs();
return refs.stream().filter(item -> !(item instanceof SymbolicRef))
.filter(item -> item.getName().startsWith(GitBranchType.REMOTE.getPrefix()))
.map(ref -> ref.getName().substring(GitBranchType.REMOTE.getPrefix().length()))
.collect(Collectors.toList());
}
}
/**
* 获取git对象
* @param gitUrl git的http路径
* @param credentialsProvider 认证
* @param localPath 本地路径
* @return
* @throws IOException
* @throws GitAPIException
*/
public static Git getGit(String gitUrl, CredentialsProvider credentialsProvider, String localPath) throws IOException, GitAPIException {
if (new File(localPath).exists() ) {
return Git.open(new File(localPath));
} else {
return Git.cloneRepository().setCredentialsProvider(credentialsProvider).setURI(gitUrl)
.setDirectory(new File(localPath)).call();
}
}
/**
* 关闭git
* @param git
*/
public static void closeGit(Git git) {
git.close();
}
/**
* 创建Git认证信息
* @param username
* @param password
* @return
*/
public static CredentialsProvider createCredentialsProvider(String username, String password) {
return new UsernamePasswordCredentialsProvider(username, password);
}
}
4、测试工具类
测试如下:
/**
* Git工具类测试
* @author chentiefeng
* @date 2021/2/10 14:02
*/
public class GitUtilsTest {
public static void main(String[] args) throws IOException, GitAPIException {
String gitUrl = "https://gitee.com/smart-it-work/smart-stream.git";
String username = "imchentiefeng@aliyun.com";
String password = "********";
String localDir = "D:\\test\\smart-stream";
CredentialsProvider credential = GitUtils.createCredentialsProvider(username, password);
Git git = GitUtils.getGit(gitUrl, credential, localDir);
List<String> localBranches = GitUtils.getBranches(git, GitBranchType.LOCAL);
List<String> remoteBranches = GitUtils.getBranches(git, GitBranchType.REMOTE);
String test = GitUtils.createBranch(git, credential, "test");
boolean flag = GitUtils.removeBranch(git, credential, "test");
boolean commitFlag = GitUtils.commitFiles(git, credential, ".", "test");
GitUtils.closeGit(git);
}
}
下一篇: JGit学习
推荐阅读
-
ES]带基本操作和官方查询指导的 JAVA 集成 ES
-
一种结构设计模式,允许在对象中动态添加新行为。它通过创建一个封装器来实现这一目的,即把对象放入一个装饰器类中,然后把这个装饰器类放入另一个装饰器类中,以此类推,形成一个封装器链。这样,我们就可以在不改变原始对象的情况下动态添加新行为或修改原始行为。 在 Java 中,实现装饰器设计模式的步骤如下: 定义一个接口或抽象类作为被装饰对象的基类。 公共接口 Component { void operation; } } 在本例中,我们定义了一个名为 Component 的接口,该接口包含一个名为 operation 的抽象方法,该方法定义了被装饰对象的基本行为。 定义一个实现基类方法的具体装饰对象。 公共类 ConcreteComponent 实现 Component { public class ConcreteComponent implements Component { @Override public void operation { System.out.println("ConcreteComponent is doing something...") ; } } 定义一个抽象装饰器类,该类继承于基类,并将装饰对象作为一个属性。 公共抽象类装饰器实现组件 { protected Component 组件 public Decorator(Component component) { this.component = component; } } @Override public void operation { component.operation; } } } 在这个示例中,我们定义了一个名为 Decorator 的抽象类,它继承了 Component 接口,并将被装饰对象作为一个属性。在操作方法中,我们调用了被装饰对象上的同名方法。 定义一个具体的装饰器类,继承自抽象装饰器类并实现增强逻辑。 公共类 ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component 组件) { super(component); } } public void operation { super.operation System.out.println("ConcreteDecoratorA 正在添加新行为......") ; } } 在本例中,我们定义了一个名为 ConcreteDecoratorA 的具体装饰器类,它继承自装饰器抽象类,并实现了操作方法的增强逻辑。在操作方法中,我们首先调用被装饰对象上的同名方法,然后添加新行为。 使用装饰器增强被装饰对象。 公共类 Main { public static void main(String args) { Component 组件 = new ConcreteComponent; component = new ConcreteDecoratorA(component); 组件操作 } } 在这个示例中,我们首先创建了一个被装饰对象 ConcreteComponent,然后通过 ConcreteDecoratorA 类创建了一个装饰器,并将被装饰对象作为参数传递。最后,调用装饰器的操作方法,实现对被装饰对象的增强。 使用场景 在 Java 中,装饰器模式被广泛使用,尤其是在 I/O 中。Java 中的 I/O 库使用装饰器模式实现了不同数据流之间的转换和增强。 让我们打开文件 a.txt,从中读取数据。InputStream 是一个抽象类,FileInputStream 是专门用于读取文件流的子类。BufferedInputStream 是一个支持缓存的数据读取类,可以提高数据读取的效率,具体代码如下: @Test public void testIO throws Exception { InputStream inputStream = new FileInputStream("C:/bbb/a.txt"); // 实现包装 inputStream = new BufferedInputStream(inputStream); byte bytes = new byte[1024]; int len; while((len = inputStream.read(bytes)) != -1){ System.out.println(new String(bytes, 0, len)); } } } } 其中 BufferedInputStream 对读取数据进行了增强。 这样看来,装饰器设计模式和代理模式似乎有点相似,接下来让我们讨论一下它们之间的区别。 第三,与代理模式的区别: 代理模式的目的是控制对对象的访问,它在对象外部提供一个代理对象来控制对原对象的访问。代理对象和原始对象通常实现相同的接口或继承相同的类,以确保两者可以相互替换。 装饰器模式的目的是动态增强对象的功能,而这是通过对象内部的包装器来实现的。在装饰器模式中,装饰器类和被装饰对象通常实现相同的接口或继承自相同的类,以确保两者可以相互替代。装饰器模式也被称为封装器模式。 在代理模式中,代理类附加了与原类无关的功能。
-
Java - 使用 Spring 的资源/资源加载器接口来操作资源文件
-
Java 操作指南:高德地图 API 的 IP 定位功能详情
-
RabbitMQ]| Lion 为您提供(超级详细的)本地 Java 操作 Rabbit 队列 - V。通配符模式
-
IOS UI 自动化测试实践:pyhton-wda 环境设置篇-Xcode 版本:10.1iphone 版本:12.0.1OS 版本:10.13.6 实践开始 创建一个新目录并从 git 下载 WDA 项目代码。 git clone https://github.com/facebook/WebDriverAgent 并运行初始化脚本。 ./Scripts/bootstrap.sh 出现以下错误信息:原因:Carthage 需要下载相关的依赖项,而这些依赖项并未在本地安装。 解决方法通过 brew 下载并安装依赖项: brew install carthage 下载成功并初始化脚本后,出现以下错误:原因:需要 npm 来打包响应 js 文件,而机器上未安装该文件。 解决方案:通过 brew 下载并安装 npm(注:brew 真的是个好东西):brew install npm 安装成功后,继续初始化脚本。/Scripts/bootstrap.sh Xcode 相关操作
-
1.5.1 使用 Git 管理本地仓库的基本操作
-
在 Java8 数据流中对三个参数的 reduce 方法进行列表分组统计操作
-
Java 中的定位和 (&)、定位或 (|) 和不同或 (^) 操作符
-
git 拉取和提交代码的具体操作流程 - 结论