如何使用java来操作git/gitlab?

在我们的学习和开发过程中,git作为一个优秀的分布式版本控制工具是经常会被我们使用到的,那么如何通过java代码来实现Git的更新,提交,推送等操作呢?下面整理了三种实现方式:
1.首先我们会想到的应该是寻找市面上是否已经有了比较成熟的、开源的git客户端。这是我推荐使用一个比较成熟的git客户端——JGit。JGit 是一个轻量级纯 Java 的类库,用来实现 Git 的版本控制系统的访问,以及提供核心的版本控制算法。EGit 这个 Eclipse 上的 Git 插件就是采用 JGit 开发的。
如果你对git和jgit还不熟悉,推荐学习书籍:pro git
下面介绍如何在代码中集成jgit:
(1)在pom.xml中引入如下依赖:

		<dependency><groupId>org.eclipse.jgit</groupId><artifactId>org.eclipse.jgit</artifactId><version>5.12.0.202106070339-r</version></dependency>

(2)编写配置类JgitConfig.java

@Configuration
@ConfigurationProperties(prefix = "jgit")
public class JgitConfig {private static String username;private static String password;public static String getUsername() {return username;}public void setUsername(String username) {JgitConfig.username = username;}public static String getPassword() {return password;}public void setPassword(String password) {JgitConfig.password = password;}
}

(3)application.yml文件配置

jgit:username: #git账号名password: #git密码

(4)编写JgitUtil工具类。(注:由于业务原因,方法中需要的localPath参数我是通过数据库获取的,大家用的时候也可以放入配置文件中配置)

@Slf4j
public class JgitUtil {/*** 生成身份信息*/private static CredentialsProvider provider = new UsernamePasswordCredentialsProvider(JgitConfig.getUsername(), JgitConfig.getPassword());public static Git openRpo(String localPath) {Git git = null;try {Repository repository = new FileRepositoryBuilder().setGitDir(Paths.get(localPath, ".git").toFile()).build();git = new Git(repository);} catch (IOException e) {e.printStackTrace();}return git;}/*** 初始化(init)——git init*/public static void init(String localPath) throws GitAPIException {Git.init().setDirectory(new File(localPath)).call();}/*** 添加到暂存区(Add)git add .* git add Delete.txt* 删除和移动的文件不能使用git.add(),需要使用git.rm()的方式,就算参数是“.”也需要使用 git.rm()方法*/public static void add(String localPath, String fileName) throws Exception {openRpo(localPath).add().addFilepattern(Optional.ofNullable(fileName).orElse(".")).call();}public static void rm(String localPath, String fileName) throws Exception {openRpo(localPath).rm().addFilepattern(fileName).call();}/*** 提交(Commit) git commit -m"first commit"*/public static void commit(String localPath, String commitInfo) throws Exception {openRpo(localPath).commit().setMessage(Optional.ofNullable(commitInfo).orElse("default commit info")).call();}/*** 移动(mv)*/public static void mv(String localPath, String sourcePath, String targetPath, File file) {System.out.println(sourcePath);try {File newDir = new File(targetPath);if (!newDir.exists()) {newDir.mkdirs();}File newFile = new File(newDir, file.getName());boolean success = file.renameTo(newFile);if (success) {add(localPath, ".");rm(localPath, sourcePath);commit(localPath, "File moved to new directory");push(localPath);} else {// handle errorlog.error("文件移动异常!");}} catch (Exception e) {e.printStackTrace();}}/*** 状态(status) git status** @throws Exception*/public static Map<String, String> status(String localPath) throws Exception {Map<String, String> map = new HashMap<>();Status status = openRpo(localPath).status().call();map.put("Added", status.getAdded().toString());map.put("Changed", status.getChanged().toString());map.put("Conflicting", status.getConflicting().toString());map.put("ConflictingStageState", status.getConflictingStageState().toString());map.put("IgnoredNotInIndex", status.getIgnoredNotInIndex().toString());map.put("Missing", status.getMissing().toString());map.put("Modified", status.getModified().toString());map.put("Removed", status.getRemoved().toString());map.put("UntrackedFiles", status.getUntracked().toString());map.put("UntrackedFolders", status.getUntrackedFolders().toString());return map;}/*** ===============================分支操作=============================*//*** 创建分支(Create Branch) git branch dev** @throws Exception*/public static void branch(String localPath, String branchName) throws Exception {openRpo(localPath).branchCreate().setName(branchName).call();}/*** 删除分支(Delete Branch) git branch -d dev** @throws Exception*/public static void delBranch(String localPath, String branchName) throws Exception {openRpo(localPath).branchDelete().setBranchNames(branchName).call();}/*** 切换分支(Checkout Branch) git checkout dev** @throws Exception*/public static void checkoutBranch(String localPath, String branchName) throws Exception {openRpo(localPath).checkout().setName(branchName).call();}/*** 所有分支(BranchList) git branch** @throws Exception*/public static List<Ref> listBranch(String localPath) throws Exception {return openRpo(localPath).branchList().call();}/*** 合并分支(Merge Branch) git merge dev** @throws Exception*/public static void mergeBranch(String localPath, String branchName, String commitMsg) throws Exception {//切换分支获取分支信息存入Ref对象里Ref refdev = openRpo(localPath).checkout().setName(branchName).call();//切换回main分支openRpo(localPath).checkout().setName("main").call();// 合并目标分支MergeResult mergeResult = openRpo(localPath).merge().include(refdev)//同时提交.setCommit(true)// 分支合并策略NO_FF代表普通合并, FF代表快速合并.setFastForward(MergeCommand.FastForwardMode.NO_FF).setMessage(Optional.ofNullable(commitMsg).orElse("master Merge")).call();}/*** ========================远端仓库操作(Repository)==============================*//*** 推送(Push) git push origin master** @throws Exception*/public static void push(String localPath) throws Exception {openRpo(localPath).push()//设置推送的URL名称如"origin".setRemote("origin")//设置需要推送的分支,如果远端没有则创建.setRefSpecs(new RefSpec("main"))//身份验证.setCredentialsProvider(provider).call();}public static void push(String localPath, String branch) throws Exception {openRpo(localPath).push()//设置推送的URL名称如"origin".setRemote("origin")//设置需要推送的分支,如果远端没有则创建.setRefSpecs(new RefSpec(branch))//身份验证.setCredentialsProvider(provider).call();}/*** /拉取(Pull) git pull origin** @throws Exception*/public static void pull(String localPath, String remotePath) throws Exception {//判断localPath是否存在,不存在调用clone方法File directory = new File(localPath);if (!directory.exists()) {gitClone(localPath, remotePath, "main");}openRpo(localPath).pull().setRemoteBranchName("main").setCredentialsProvider(provider).call();}public static void pull(String localPath, String remotePath, String branch) throws Exception {//判断localPath是否存在,不存在调用clone方法File directory = new File(localPath);if (!directory.exists()) {gitClone(localPath, remotePath, branch);}openRpo(localPath).pull().setRemoteBranchName(branch).setCredentialsProvider(provider).call();}/*** 克隆(Clone) git clone https://xxx.git** @throws Exception*/public static void gitClone(String localPath, String remotePath, String branch) throws Exception {//克隆Git git = Git.cloneRepository().setURI(remotePath).setDirectory(new File(localPath)).setCredentialsProvider(provider)//设置是否克隆子仓库.setCloneSubmodules(true)//设置克隆分支.setBranch(branch).call();//关闭源,以释放本地仓库锁git.getRepository().close();git.close();}
}

(5)直接在对应的业务代码中调用上述工具类中的方法即可。
如果有些朋友还需要集成其他命令,可以了解下这个开源项目:https://github.com/centic9/jgit-cookbook,git的几乎所有操作都在这里面集成了。
2.另外一种方式大家想必也猜到了。既然可以在命令行中执行git命令来操作git,那么能不能通过使用java控制终端来执行git命令呢?答案是肯定的,但前提是需要在你电脑或服务器上先安装好git客户端。
下面是示例代码:

@Slf4j
public class GitUtils {public static String executeCommand(String command) {StringBuilder output = new StringBuilder();Process process;try {process = Runtime.getRuntime().exec(command);process.waitFor();BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {output.append(line).append("\n");}} catch (IOException | InterruptedException e) {e.printStackTrace();}return output.toString();}public static void cloneRepository(String remotePath, String localPath) {String command = "git clone " + remotePath + " " + localPath;String output = executeCommand(command);System.out.println(output);}public static void pull(String localPath,String branch) {String command = "git -C " + localPath + " pull origin "+branch;String output = executeCommand(command);System.out.println(output);}public static void checkoutBranch(String localPath, String branchName) {String command = "git -C " + localPath + " checkout " + branchName;String output = executeCommand(command);System.out.println(output);}public static void commit(String localPath, String message) {String command = "git -C " + localPath + " commit -a -m \"" + message + "\"";String output = executeCommand(command);System.out.println(output);}public static void add(String localPath) {String command = "git -C " + localPath + " add .";String output = executeCommand(command);System.out.println(output);}public static void push(String localPath) {String command = "git -C " + localPath + " push";String output = executeCommand(command);System.out.println(output);}public static void mv(File file,String localPath){File newDir = new File(localPath);if (!newDir.exists()) {newDir.mkdirs();}File newFile = new File(newDir, file.getName());boolean success = file.renameTo(newFile);if (success) {add(localPath);commit(localPath,"File moved to new directory");push(localPath);} else {// handle errorlog.error("文件移动异常!");}}
}

3.如果你的git服务端使用的是gitlab,还可以使用gitlab的api来操作。下面是具体的实现操作:
(1)在gitlab中配置访问令牌。
在这里插入图片描述

(2)pom.xml文件中引入依赖。

 <dependency><groupId>org.gitlab4j</groupId><artifactId>gitlab4j-api</artifactId><version>4.19.0</version></dependency>

(3)编写配置类,并在yml文件中配置。

@Configuration
@ConfigurationProperties(prefix = "git")
public class GitConfig {public static String hostUrl;public static String personalAccessToken;public static String getHostUrl() {return hostUrl;}public static void setHostUrl(String hostUrl) {GitConfig.hostUrl = hostUrl;}public static String getPersonalAccessToken() {return personalAccessToken;}public static void setPersonalAccessToken(String personalAccessToken) {GitConfig.personalAccessToken = personalAccessToken;}
}
git:hostUrl: #gitlab访问的ip+端口,如:http://127.0.0.1:8080personalAccessToken: #刚刚配置的访问令牌

(4)编写工具类。(注:gitProjId,branch,filePath都可写入配置文件中,gitProjId为gitlab中对应的项目id,filePath为git本地文件路径)

public class GitLabApiUtils {private static GitLabApi gitLabApi = new GitLabApi(GitConfig.hostUrl, GitConfig.personalAccessToken, null,null);public static InputStream getRawFileStreamByProjId(Integer gitProjId, String branch, String filePath) throws GitLabApiException {return   gitLabApi.getRepositoryFileApi().getRawFile(gitProjId,branch,filePath);}public static InputStream getRawFileStreamByGitPath(String gitPath,String branch,String filePath) throws GitLabApiException {return   gitLabApi.getRepositoryFileApi().getRawFile(gitPath,branch,filePath);}public static RepositoryFile getFile(Integer projectId, String filepath, String branch) throws GitLabApiException {return gitLabApi.getRepositoryFileApi().getFile(projectId, filepath, branch);}public static Optional<RepositoryFile> getOptionalFile(Integer projectId, String filepath, String branch) throws GitLabApiException {return gitLabApi.getRepositoryFileApi().getOptionalFile(projectId, filepath, branch);}public static List<Project> getProjects() throws GitLabApiException {return gitLabApi.getProjectApi().getProjects();}//查询文件树结构public static List<TreeItem> getFileTree(Integer gitProjId, String branch, String filePath) throws GitLabApiException {return gitLabApi.getRepositoryApi().getTree(gitProjId,filePath,branch,true);//默认递归查询}//获取blob文件列表public static List<TreeItem> getFileList(Integer gitProjId, String branch, String filePath) throws GitLabApiException {List<TreeItem> tree = gitLabApi.getRepositoryApi().getTree(gitProjId, filePath, branch, true);//默认递归查询  筛选出文件后返回listArrayList<TreeItem> treeItems = new ArrayList<>();for (TreeItem treeItem : tree) {if ("blob".equals(treeItem.getType().toString()) ) {treeItems.add(treeItem);}}return  treeItems;}public static List<TreeItem> getFileList(String projectPath, String branch, String filePath) throws GitLabApiException {return gitLabApi.getRepositoryApi().getTree(projectPath,filePath,branch,true);//默认递归查询  筛选出文件后返回list}public static synchronized RepositoryFile createFile(Integer gitProjId , RepositoryFile file, String branch, String commit) throws GitLabApiException {return  gitLabApi.getRepositoryFileApi().createFile(gitProjId,file,branch,commit);}public static synchronized RepositoryFile updateFile(Integer gitProjId , RepositoryFile file, String branch, String commit) throws GitLabApiException {return  gitLabApi.getRepositoryFileApi().updateFile(gitProjId,file,branch,commit);}public static RepositoryFile getFileByProjId(Integer gitProjId,String branch,String filePath) throws GitLabApiException {return   gitLabApi.getRepositoryFileApi().getFile(gitProjId,filePath,branch);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/444578.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年【煤炭生产经营单位(安全生产管理人员)】考试题及煤炭生产经营单位(安全生产管理人员)试题及解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 煤炭生产经营单位&#xff08;安全生产管理人员&#xff09;考试题是安全生产模拟考试一点通生成的&#xff0c;煤炭生产经营单位&#xff08;安全生产管理人员&#xff09;证模拟考试题库是根据煤炭生产经营单位&…

Flink实战五_状态机制

接上文&#xff1a;Flink实战四_TableAPI&SQL 在学习Flink的状态机制之前&#xff0c;我们需要理解什么是状态。回顾我们之前介绍的很多流计算的计算过程&#xff0c;有些计算方法&#xff0c;比如说我们之前多次使用的将stock.txt中的一行文本数据转换成Stock股票对象的ma…

某赛通电子文档安全管理系统 PolicyAjax SQL注入漏洞复现

0x01 产品简介 某赛通电子文档安全管理系统(简称:CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护,系统具有透明加密、主动加密、智能…

TypeScript实战教程(一):表单上传与后端处理

TypeScript实战教程&#xff08;一&#xff09;&#xff1a;表单上传与后端处理 文章目录 TypeScript实战教程&#xff08;一&#xff09;&#xff1a;表单上传与后端处理一、前言1、TypeScript介绍2、TypeScript的关键特性包括&#xff1a;3、使用场景4、编译过程 二、环境配置…

【RT-DETR有效改进】 利用Damo-YOLO的RepGFPN改进特征融合层(高效重参数化Neck)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文给大家带来的改进机制是Damo-YOLO的RepGFPN(重参数化泛化特征金字塔网络),利用其优化RT-DETR的Neck部分,可以在不影响计算量的同时大幅度涨点(亲测在小目标和大目标检测的数据集上效果均表现良好涨点幅…

Python代码重构库之rope使用详解

概要 Python是一门强大的编程语言,但在大型项目中,维护和重构代码可能会变得复杂和困难。为了提高开发人员的效率和准确性,有许多工具可用于辅助代码重构和智能代码补全。其中之一是Python Rope。 Python Rope是一个用于Python编程语言的强大工具,它提供了丰富的功能,包…

Idea编写mapper.xml文件提示表名和字段

一、连接database 二、setting- > language -> sql Dialects中 的选项设为 mysql就可以了 三、测试

接口自动化代码不会写?试试RunnerGo

RunnerGo支持自动化测试功能&#xff0c;RunnerGo的工作流程是&#xff1a;接口管理-场景管理-性能测试-自动化测试&#xff0c;所以自动化测试的运行内容为场景下的用例&#xff0c;我们可以在“场景管理”中预先配置好该场景下的用例&#xff0c;也可以在自动化测试中创建用例…

VSCode 设置代理

Open Visual Studio Code, click the settings icon in the lower left corner, and click Settings.

【SpringBoot3】Spring 请求处理流程,自定义返回类型处理(HttpMessageConverter)

一、Spring Boot 请求处理 1、请求处理流程 Spring Boot 的接口请求处理流程主要基于 Spring MVC 架构&#xff0c;以下是详细的请求处理流程&#xff1a; 客户端发送请求&#xff1a;客户端发送HTTP请求到Spring Boot应用的URL。 DispatcherServlet 接收请求&#xff1a;Sp…

stm32--simulink开发之--timer的学习,硬件输入中断,触发事件,STM32通用定时器之输出比较模式与PWM模式(重要理解)

下面三个模块&#xff0c;一个比一个高级&#xff0c;当然使用是越来越简单 1&#xff0c;第一个模块&#xff1a;Timer Starts timer counter and provides current counter value Timer Starts Timer Counter and Provides Current Counter Value: 这个模块启动定时器计数器…

架构师应知必会的缩写大全

架构师应知必会的缩写大全 本文转自 公众号 ByteByteGo&#xff0c;如有侵权&#xff0c;请联系&#xff0c;立即删除 CAP、BASE、SOLID、KISS&#xff0c;这些缩写词是什么意思&#xff1f; 下图解释了系统设计中常见的缩写词。 CAP CAP 定理指出&#xff0c;任何分布式数据…