【JGit 】一个完整的使用案例

需求

生成一系列结构相同的项目代码,将这些项目的代码推送至一个指定的 Git 仓库,每个项目独占一个分支。

推送时若仓库不存在,则自动创建仓库。

分析

生成代码使用 Java 程序模拟,每个项目中模拟三个文件。Project.cppProject.hREADME

使用 JGit 实现代码版本管理与推送。

代码实现

以下代码包含了代码生成,Git 仓库初始化、代码克隆、分支检出、代码修改、暂存、提交及推送等操作。

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;import cn.hutool.core.io.FileUtil;public class JgitTest3 {private static String DEFAULE_REMOTE_NAME = "origin";private static String DEFAULE_BRANCH_NAME = "master";private static String gitUrl = "http://192.168.181.1:3000/root/a-test.git";private static String username = "root";private static String password = "123456";/*** 创建认证信息* * @return*/public static CredentialsProvider getCredentialsProvider() {return new UsernamePasswordCredentialsProvider(username, password);}public static void main(String[] args) throws Exception {List<String> branches = Stream.of("branchA", "branchB").collect(Collectors.toList());for (String branchName : branches) {System.out.println("\r\n ==========================<<" + branchName + ">>==========================\r\n");// 生成代码File codeDir = genCode(branchName);System.out.println(" >>>>>>>>>>>>>>> CodeDir: " + codeDir);// 判断仓库是否存在boolean remoteRepositoryExist = remoteRepositoryExist(gitUrl, username, password);if (remoteRepositoryExist) {pushOnRepoExist(branchName, codeDir);} else {pushOnRepoNotExist(branchName, codeDir);}// 清理生成的文件FileUtil.del(codeDir);}}private static void pushOnRepoNotExist(String branchName, File codeDir) throws Exception {// 将源码库初始化为Git仓库Git git = Git.init().setDirectory(codeDir).call();// 添加远程仓库git.remoteAdd().setName(DEFAULE_REMOTE_NAME).setUri(new URIish(gitUrl)).call();// 初始化提交git.add().addFilepattern(".").call();git.commit().setMessage("Initial commit").call();// 切换分支checkoutBranch(git, branchName);// 提交推送pushToRepo(git, branchName);// 关闭资源git.close();}private static void pushOnRepoExist(String branchName, File codeDir) throws Exception {// 创建临时工作目录File localDir = Files.createTempDirectory("Jgit-work-dir-").toFile();System.out.println("\r\n >>>>>>>>>>>>>>> Work dir is: " + localDir + "\r\n");// 克隆到本地Git git = Git.cloneRepository().setDirectory(localDir).setURI(gitUrl).setCredentialsProvider(getCredentialsProvider()).call();// 切换到分支checkoutBranch(git, branchName);// 更新代码deleteContent(localDir.toPath(), ".git");// git.add().addFilepattern(".").setUpdate(true).call();// git.commit().setMessage("rm origin files").call();FileUtil.copyContent(codeDir, localDir, true);// 提交、推送pushToRepo(git, branchName);// 关闭资源git.close();FileUtil.del(localDir);}/*** 推送到远端分支* * @param git* @param branchName 远端分支* @throws Exception*/private static Iterable<PushResult> pushToRepo(Git git, String branchName) throws Exception {// 加入暂存区git.add().addFilepattern(".").call();git.add().addFilepattern(".").setUpdate(true).call();// 提交git.commit().setMessage(" Commit at : " + LocalDateTime.now()).call();// 构建推送命令PushCommand pushCmd = git.push().setRemote(DEFAULE_REMOTE_NAME).setCredentialsProvider(getCredentialsProvider());Ref remoteBranchRef = git.getRepository().findRef("refs/remotes/" + DEFAULE_REMOTE_NAME + "/" + branchName);if (Objects.isNull(remoteBranchRef)) {pushCmd.add(branchName);} else {pushCmd.setForce(true);}// 推送return pushCmd.call();}/*** 切换分支* <p>* <ul>* <li>先判断本地分支是否存在,存在则直接切换,不存在则下一步。</li>* <li>判断远程分支是否存在,存在则直接切换,不存在则在切换时创建分支。</li>* </ul>* * </p>* * @param git* @param branchName*/private static void checkoutBranch(Git git, String branchName) throws Exception {CheckoutCommand checkoutCmd = git.checkout().setName(branchName);Repository repository = git.getRepository();Ref branchRef = repository.findRef("refs/heads/" + branchName);if (Objects.isNull(branchRef)) {Ref remoteBranchRef = repository.findRef("refs/remotes/" + DEFAULE_REMOTE_NAME + "/" + branchName);if (Objects.isNull(remoteBranchRef)) {CreateBranchCommand createBranchCmd = git.branchCreate().setName(branchName);// 先切换到已有分支,以获取提交记录,设置提交点辅助创建新的分支List<Ref> branches = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call();if (Objects.nonNull(branches) && branches.size() > 0) {Ref remoteRef = branches.get(0);String bName = Repository.shortenRefName(remoteRef.getName());git.checkout().setName(bName).call();RevCommit latestCommit = git.log().setMaxCount(1).call().iterator().next();if (Objects.nonNull(latestCommit)) {createBranchCmd.setStartPoint(latestCommit);}}createBranchCmd.call();} else {checkoutCmd.setCreateBranch(true);}}checkoutCmd.call();}/*** 删除目录中的所有文件* <ul>* <li>文件</li>* <li>文件夹</li>* <li>子文件</li>* <li>子文件夹</li>* </ul>* * @param folderPath  目标文件夹* @param ignoreFiles 忽略的文件或文件夹*/public static void deleteContent(Path folderPath, String... ignoreFiles) {try {Files.walk(folderPath).filter(path -> !path.equals(folderPath)).filter(path -> {if (Objects.isNull(ignoreFiles) || ignoreFiles.length == 0) {return false;}for (String ig : ignoreFiles) {if (StringUtils.contains(path.toAbsolutePath().toString(), ig)) {return false;}}return true;}).forEach(path -> {try {if (path.toFile().isDirectory()) {deleteContent(path, ignoreFiles);} else {Files.deleteIfExists(path);}} catch (IOException e) {e.printStackTrace();}});} catch (IOException e) {e.printStackTrace();}}/*** 生成代码* * @param branchName* @return* @throws Exception*/private static File genCode(String branchName) throws Exception {File codeDir = Files.createTempDirectory("Jgit-source-dir-").toFile();String codeDirAbsPath = codeDir.getAbsolutePath();// 生成 READMEFile addNewFile = new File((codeDirAbsPath.concat(File.separator).concat("README.md")));String readmeContent = "Project for " + branchName + "\r\nWrite By Code JGitTest ";Files.write(addNewFile.toPath(), readmeContent.getBytes());// 生成文件File cppFile = new File(codeDirAbsPath.concat(File.separator).concat(branchName.concat(".cpp")));String cppContent = "Cpp Code for " + branchName + "\r\n Write By Code JGitTest ";Files.write(cppFile.toPath(), cppContent.getBytes());// 生成文件File hFile = new File(codeDirAbsPath.concat(File.separator).concat(branchName.concat(".h")));String hContent = "Header code for " + branchName + "\r\nWrite By Code JGitTest ";Files.write(hFile.toPath(), hContent.getBytes());return codeDir;}/*** 判断远程仓库是不是存在** @param remoteUrl 远程仓库地址* @return true(存在)/false(不存在)*/public static boolean remoteRepositoryExist(String remoteUrl, String username, String password) {try {Collection<Ref> refs = (Collection<Ref>) Git.lsRemoteRepository().setHeads(true).setTags(true).setCredentialsProvider(getCredentialsProvider(username, password)).setRemote(remoteUrl).call();if (refs.isEmpty()) {return false;} else {return true;}} catch (Exception e) {log.warn("仓库{}不存在", remoteUrl);return false;}}}

成果展示

在这里插入图片描述

1、JGit 版本

        <!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit --><dependency><groupId>org.eclipse.jgit</groupId><artifactId>org.eclipse.jgit</artifactId><version>5.1.3.201810200350-r</version></dependency>

2、Gitea 安装

  • Win 下 Docker 安装 Gitea 实践:windows docker desktop部署gitea

3、JGit 资料

  • 【JGit】简述及学习资料整理
  • 【Gitea】Java 使用 JGit 创建 Git 代码仓库
  • 【Git】 删除远程分支
  • 【Gitea】配置 Push To Create

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

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

相关文章

更改elementui的箭头图片以及位置

//更改箭头位置 .el-tree-node__content > .el-tree-node__expand-icon {position: absolute;right: 12px; }//更改箭头图片 .el-tree-node__expand-icon {transform: rotate(-90deg); } .el-tree-node__expand-icon.expanded {transform: rotate(0deg); } // 有子节点 且已…

qml系列文章目录总览

qml中的信号槽的几种方式 qml中获取Loader加载的顶层对象 qml中QtObject类型的使用 qml与C的交互 qml中Repeter类型的使用 qml中访问控件内部的子项 qml中利用SwipeView和PageIndicator制作轮播图 qml中的default默认属性 qml中StackView的使用 qml 中 row与rowlayout的区别 qm…

TypeScript + react 中 TypeScript 的加入后 , 有哪些优化项目

在使用 TypeScript 结合 React 进行开发时&#xff0c;TypeScript 提供了许多优化和增强代码质量的方式。以下是一些关键的优化操作和最佳实践&#xff1a; 强类型组件属性&#xff08;Props&#xff09;和状态&#xff08;State&#xff09;: 使用接口或类型别名定义组件的 pr…

C++面试 -分布式架构-架构能力:分布式事务的学习

目录 1. 分布式事务的基本概念 2. 分布式事务的需求背景 3. 分布式事务的实现方式 1. 两阶段提交&#xff08;2PC&#xff09; 2. 三阶段提交&#xff08;3PC&#xff09; 3. 补偿事务&#xff08;Saga&#xff09; 4. 分布式事务协调器 4. 分布式事务的挑战 5. 面试准…

QEMU之内存虚拟化

内存虚拟化方案 最直观的方案&#xff0c;将QEMU进程的虚拟地址空间的一部分作为虚拟机的物理地址。但该方案有一个问题&#xff1a; 在物理机上&#xff0c;CPU对内存的访问在保护模式下是通过分段分页实现的&#xff0c;在该模式下&#xff0c;CPU访问时使用的是虚拟地址&am…

Unity绘制六边形体

现在steam上面有很多下棋类/经营类的游戏都是用六边形的地形&#xff0c;比较美观而且实用&#xff0c;去年在版本末期我也自己尝试做了一个绘制六边体的demo&#xff0c;一年没接触unity竟然都要忘光了&#xff0c;赶紧在这边记录一下。 想cv代码可以直接拉到代码章节 功能 …

音频转换器哪个好?3款电脑软件+3款手机应用

在当今的数字时代&#xff0c;音频转换已成为许多用户日常的需求。为了帮助您找到最佳的音频转换工具&#xff0c;我们将介绍3款电脑软件和3款手机应用。这些工具都各有特点&#xff0c;能够满足不同用户的需求。 1.电脑软件篇 1.1金舟音频大师 金舟音频大师是一款多功能的音…

提取天猫店铺商家电话的爬虫软件

在日常生活中&#xff0c;我们经常会遇到需要获取商家电话的情况&#xff0c;比如想要咨询商品信息、预约服务等。而天猫作为国内知名的电商平台&#xff0c;拥有众多的商家店铺&#xff0c;如果能够快速提取店铺商家电话&#xff0c;就能够方便我们与商家进行沟通。 为了实现…

【LabVIEW 】串口如何读取长度不一致的字符串

工程经验 1、在循环中&#xff0c;加入定时器&#xff0c;这样可以一段时间读取一次。 2、只要获取完整的一帧数据&#xff0c;就可以进行过滤筛选。

力扣128. 最长连续序列(哈希表)

Problem: 128. 最长连续序列 文章目录 题目描述思路复杂度Code 题目描述 思路 1.先将数组中的元素存入到一个set集合中&#xff08;去除重复的元素&#xff09; 2.欲找出最长连续序列&#xff08;先定义两个int变量longestSequence和currentSequence用于记录最长连续序列和当前…

Adobe Acrobat DC中如何合并pdf并生成目录

一、利用 Acrobat 合成pdf目录 &#xff08;一&#xff09;新建标签&#xff08;更改标签等级等&#xff09; 1&#xff0c;用Adobe acrobat 软件打开待添加书签的pdf文档。 2&#xff0c;打开之后点击软件左边栏的书签&#xff08;有时被隐藏了&#xff0c;点击一下界面左边…

企业服务器有哪些作用?

企业服务器是企业信息系统的核心组成部分&#xff0c;能够提高企业的工作效率&#xff0c;那么企业服务器具体都有哪些作用呢&#xff1f; 企业服务器的作用主要有以下几个方面&#xff1a; 企业服务器有着虚拟化技术&#xff0c;可以将一台物理服务器分为多个虚拟服务器&#…

第一节 数据操作+数据处理

本系列文章为李沐老师《动手学深度学习》Pytorch版实践学习笔记&#xff0c;相关课程教学、书籍、代码均为开源&#xff0c;可通过以下链接参考学习&#xff1a; 跟李沐学AI的个人空间-跟李沐学AI个人主页-哔哩哔哩视频 (bilibili.com) 前言 — 动手学深度学习 2.0.0 documenta…

高校物品捐赠管理系统|基于springboot高校物品捐赠管理系统设计与实现(源码+数据库+文档)

高校物品捐赠管理系统目录 目录 基于springboot高校物品捐赠管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、捐赠信息管理 3、论坛信息管理 4、公告信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算…

RabbitMQ讲解与整合

RabbitMq安装 类型概念 租户 RabbitMQ 中有一个概念叫做多租户&#xff0c;每一个 RabbitMQ 服务器都能创建出许多虚拟的消息服务器&#xff0c;这些虚拟的消息服务器就是我们所说的虚拟主机&#xff08;virtual host&#xff09;&#xff0c;一般简称为 vhost。 每一个 vhos…

NLP-词向量、Word2vec

Word2vec Skip-gram算法的核心部分 我们做什么来计算一个词在中心词的上下文中出现的概率&#xff1f; 似然函数 词已知&#xff0c;它的上下文单词的概率 相乘。 然后所有中心词的这个相乘数 再全部相乘&#xff0c;希望得到最大。 目标函数&#xff08;代价函数&#xff0…

如何用CDH+Apache DolphinScheduler开启Kerberos

搭建环境 多台linux主机搭建集群CDH 6.3.2 (Parcel)版本Apache DolphinScheduler1.3.2版本&#xff0c;本流程在CDH已搭建完成并可正常使用后&#xff0c;开启kerberos功能&#xff0c;Apache DolphinScheduler用于大数据任务管理与执行&#xff0c;是很不错的任务调度平台&am…

ZYNQ--MIG核配置

文章目录 MIG核配置界面多通道AXI读写DDR3MIG核配置界面 Clock Period: DDR3 芯片运行时钟周期,这个参数的范围和 FPGA 的芯片类型以及具体类型的速度等级有关。本实验选择 1250ps,对应 800M,这是本次实验所采用芯片可选的最大频率。注意这个时钟是 MIG IP 核产生,并输出给…

压缩视频大小的软件有哪些?5款软件推荐

压缩视频大小的软件有哪些&#xff1f;随着高清摄像设备的普及和网络速度的不断提升&#xff0c;视频文件变得越来越庞大&#xff0c;动辄数百兆甚至数GB的大小常常让用户在分享和存储时感到头疼。幸运的是&#xff0c;市面上有许多优秀的视频压缩软件可以帮助我们轻松应对这一…

GPTs - 定制版的ChatGPT

GPTs指的是定制版的ChatGPT (Custom versions of ChatGPT)&#xff0c;它试图解决为不同用途定制ChatGPT的需求。为了实现这一点&#xff0c; GPTs 提供了指令 (Instructions)&#xff0c;知识 (Knowledge)&#xff0c;能力 (Capabilities)&#xff0c;动作 (Actions) 等功能&…