【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); } // 有子节点 且已…

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金舟音频大师 金舟音频大师是一款多功能的音…

【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;点击一下界面左边…

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

本系列文章为李沐老师《动手学深度学习》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;市面上有许多优秀的视频压缩软件可以帮助我们轻松应对这一…

NFS服务器挂载失败问题

问题 mount.nfs: requested NFS version or transport protocol is not supported背景&#xff1a;现在做嵌入式开发&#xff0c;需要在板端挂载服务器&#xff0c;读取服务器文件。挂载中遇到该问题。 挂载命令长这样 mount -t nfs -o nolock (XXX.IP):/mnt/disk1/zixi01.ch…

vue实现水印功能

目录 一、应用场景 二、实现原理 三、详细开发 1.水印的实现方式 2.防止用户通过控制台修改样式去除水印效果&#xff08;可跳过&#xff0c;有弊端&#xff09; 3.水印的使用 &#xff08;1&#xff09;单页面/全局使用 &#xff08;2&#xff09;全局使用个别页面去掉…

绘制窗口及窗口位置变化

为了方便窗口的移动 &#xff0c;及相交窗口关闭之后被遮挡窗口的重绘&#xff0c;因此给每个窗口建立一个内存BUF&#xff0c;等到不涉及内容变更的重绘&#xff0c;只需要将该BUF复制到显存之中。 然而&#xff0c;重绘时存在一个被遮挡时如何操作的问题。比如下图中依次为从…

【QT+JS】QT和JS 中的正则表达式 、QT跑JS语言

【QTJS】QT和JS 中的正则表达式 、QT跑JS语言 前言正则表达式QT 中的使用QRegExp自带的cap方法怎么用&#xff1f;QRegExp的非贪婪模式与贪婪模式 JS 中的使用 QT 跑JS 语言 前言 在看大佬的系统代码时候&#xff0c;对其中灵活用到的正则表达式和QT 跑JS 语言部分感觉很陌生&…

iOS App冷启动优化:二进制重排

原理 二进制文件中方法的加载顺序&#xff0c; 取决于方法在代码文件中的书写顺序&#xff0c;而不是调用顺序。 应用程序启动时会调用到的方法是有限的&#xff0c;但可能分散在很多个。 由于内存是分页管理的&#xff0c;要加载就要 整页加载。 这就导致很多完全还用不到的方…

网站添加pwa操作和配置manifest.json后,没有效果排查问题

pwa技术官网&#xff1a;https://web.dev/learn/pwa 应用清单manifest.json文件字段说明&#xff1a;https://web.dev/articles/add-manifest?hlzh-cn Web App Manifest&#xff1a;Web App Manifest | MDN 当网站添加了manifest.json文件后&#xff0c;也引入到html中了&a…