java中使用svnkit实现文件的版本管理
java中使用svnkit实现文件的版本管理
- 一、引入svnKit依赖
- 二、初始化仓库工厂类
- 二、使用svnkit创建本地存储仓库
- 三、svn基本原子操作
- 四、通过原子方法实现简单svn相应操作
一、引入svnKit依赖
<dependency><groupId>org.tmatesoft.svnkit</groupId><artifactId>svnkit</artifactId><version>1.9.3</version></dependency>
二、初始化仓库工厂类
本文参考来自于svnkit官网
在使用svn客户端进行各种操作时第一步需要初始化仓库工厂
/** Initializes the library to work with a repository via* different protocols.*/private static void setupLibrary() {/** For using over http:// and https://*/DAVRepositoryFactory.setup();/** For using over svn:// and svn+xxx://*/SVNRepositoryFactoryImpl.setup();/** For using over file:///*/FSRepositoryFactory.setup();}
二、使用svnkit创建本地存储仓库
try {String tgtPath = "d:/modelFiles/repos";SVNURL tgtURL = SVNRepositoryFactory.createLocalRepository( new File( tgtPath ), true , false );} catch ( SVNException e ) {//handle exception}
执行完这一段代码之后,我们可以在本地目录下发现以下目录结构
三、svn基本原子操作
private static SVNClientManager ourClientManager;private static ISVNEventHandler myCommitEventHandler;private static ISVNEventHandler myUpdateEventHandler;private static ISVNEventHandler myWCEventHandler;/** Puts directories and files under version control scheduling them for addition* to a repository. They will be added in a next commit. Like 'svn add PATH'* command. It's done by invoking** SVNWCClient.doAdd(File path, boolean force,* boolean mkdir, boolean climbUnversionedParents, boolean recursive)** which takes the following parameters:** path - an entry to be scheduled for addition;** force - set to true to force an addition of an entry anyway;** mkdir - if true doAdd(..) creates an empty directory at path and schedules* it for addition, like 'svn mkdir PATH' command;** climbUnversionedParents - if true and the parent of the entry to be scheduled* for addition is not under version control, then doAdd(..) automatically schedules* the parent for addition, too;** recursive - if true and an entry is a directory then doAdd(..) recursively* schedules all its inner dir entries for addition as well.*/// 将文件纳入版本控制private static void addEntry(File wcPath) throws SVNException {ourClientManager.getWCClient().doAdd(wcPath, false, false, false, true);}/** Updates a working copy (brings changes from the repository into the working copy).* Like 'svn update PATH' command; It's done by invoking** SVNUpdateClient.doUpdate(File file, SVNRevision revision, boolean recursive)** which takes the following parameters:** file - a working copy entry that is to be updated;** revision - a revision to which a working copy is to be updated;** recursive - if true and an entry is a directory then doUpdate(..) recursively* updates the entire directory, otherwise - only child entries of the directory;*/// 将本地文件更新到指定版本,前提是本地有该文件的其他版本private static long update(File wcPath,SVNRevision updateToRevision, boolean isRecursive)throws SVNException {SVNUpdateClient updateClient = ourClientManager.getUpdateClient();/** sets externals not to be ignored during the update*/updateClient.setIgnoreExternals(false);/** returns the number of the revision wcPath was updated to*/return updateClient.doUpdate(wcPath, updateToRevision, isRecursive);}/** Checks out a working copy from a repository. Like 'svn checkout URL[@REV] PATH (-r..)'* command; It's done by invoking** SVNUpdateClient.doCheckout(SVNURL url, File dstPath, SVNRevision pegRevision,* SVNRevision revision, boolean recursive)** which takes the following parameters:** url - a repository location from where a working copy is to be checked out;** dstPath - a local path where the working copy will be fetched into;** pegRevision - an SVNRevision representing a revision to concretize* url (what exactly URL a user means and is sure of being the URL he needs); in other* words that is the revision in which the URL is first looked up;** revision - a revision at which a working copy being checked out is to be;** recursive - if true and url corresponds to a directory then doCheckout(..) recursively* fetches out the entire directory, otherwise - only child entries of the directory;*/// svn检出操作,即从svn仓库拉取指定版本的代码private static long checkout(SVNURL url,SVNRevision revision, File destPath, boolean isRecursive)throws SVNException {SVNUpdateClient updateClient = ourClientManager.getUpdateClient();/** sets externals not to be ignored during the checkout*/updateClient.setIgnoreExternals(false);/** returns the number of the revision at which the working copy is*/return updateClient.doCheckout(url, destPath, revision, revision, isRecursive);}/** Committs changes in a working copy to a repository. Like* 'svn commit PATH -m "some comment"' command. It's done by invoking** SVNCommitClient.doCommit(File[] paths, boolean keepLocks, String commitMessage,* boolean force, boolean recursive)** which takes the following parameters:** paths - working copy paths which changes are to be committed;** keepLocks - if true then doCommit(..) won't unlock locked paths; otherwise they will* be unlocked after a successful commit;** commitMessage - a commit log message;** force - if true then a non-recursive commit will be forced anyway;** recursive - if true and a path corresponds to a directory then doCommit(..) recursively* commits changes for the entire directory, otherwise - only for child entries of the* directory;*/// svn提交操作,将本地文件提交到svn仓库private static SVNCommitInfo commit(File wcPath, boolean keepLocks, String commitMessage)throws SVNException {/** Returns SVNCommitInfo containing information on the new revision committed* (revision number, etc.)*/return ourClientManager.getCommitClient().doCommit(new File[] { wcPath }, keepLocks,commitMessage, false, true);}/** Imports an unversioned directory into a repository location denoted by a* destination URL (all necessary parent non-existent paths will be created* automatically). This operation commits the repository to a new revision.* Like 'svn import PATH URL (-N) -m "some comment"' command. It's done by* invoking** SVNCommitClient.doImport(File path, SVNURL dstURL, String commitMessage, boolean recursive)** which takes the following parameters:** path - a local unversioned directory or singal file that will be imported into a* repository;** dstURL - a repository location where the local unversioned directory/file will be* imported into; this URL path may contain non-existent parent paths that will be* created by the repository server;** commitMessage - a commit log message since the new directory/file are immediately* created in the repository;** recursive - if true and path parameter corresponds to a directory then the directory* will be added with all its child subdirictories, otherwise the operation will cover* only the directory itself (only those files which are located in the directory).*/// 本地目录初始提交到svn仓库private static SVNCommitInfo importDirectory(File localPath, SVNURL dstURL, String commitMessage, boolean isRecursive) throws SVNException{/** Returns SVNCommitInfo containing information on the new revision committed* (revision number, etc.)*/return ourClientManager.getCommitClient().doImport(localPath, dstURL, commitMessage, isRecursive);}/** Schedules directories and files for deletion from version control upon the next* commit (locally). Like 'svn delete PATH' command. It's done by invoking** SVNWCClient.doDelete(File path, boolean force, boolean dryRun)** which takes the following parameters:** path - an entry to be scheduled for deletion;** force - a boolean flag which is set to true to force a deletion even if an entry* has local modifications;** dryRun - set to true not to delete an entry but to check if it can be deleted;* if false - then it's a deletion itself.*/// svn删除操作private static void delete(File wcPath, boolean force) throws SVNException {ourClientManager.getWCClient().doDelete(wcPath, force, false);}// svn删除整个工作目录操作public static SVNCommitInfo deleteDir(ISVNEditor editor , String dirPath ) throws SVNException {editor.openRoot( -1 );editor.deleteEntry( dirPath , -1 );//Closes the root directory.editor.closeDir( );return editor.closeEdit( );}// 创建指定版本分支private static SVNCommitInfo copy(SVNURL srcURL, SVNURL dstURL,SVNRevision revision,boolean isMove, String commitMessage) throws SVNException {/** SVNRevision.HEAD means the latest revision.* Returns SVNCommitInfo containing information on the new revision committed* (revision number, etc.)*/SVNCopySource[] sources = {new SVNCopySource(null, revision, srcURL)};return ourClientManager.getCopyClient().doCopy(sources , dstURL, false, false, true, commitMessage, null);}/** Called recursively to obtain all entries that make up the repository tree* repository - an SVNRepository which interface is used to carry out the* request, in this case it's a request to get all entries in the directory* located at the path parameter;* * path is a directory path relative to the repository location path (that* is a part of the URL used to create an SVNRepository instance);* */// 打印指定版本下的文件列表信息public static void listEntries(SVNRepository repository, String path, Long version)throws SVNException {/** Gets the contents of the directory specified by path at the latest* revision (for this purpose -1 is used here as the revision number to* mean HEAD-revision) getDir returns a Collection of SVNDirEntry* elements. SVNDirEntry represents information about the directory* entry. Here this information is used to get the entry name, the name* of the person who last changed this entry, the number of the revision* when it was last changed and the entry type to determine whether it's* a directory or a file. If it's a directory listEntries steps into a* next recursion to display the contents of this directory. The third* parameter of getDir is null and means that a user is not interested* in directory properties. The fourth one is null, too - the user* doesn't provide its own Collection instance and uses the one returned* by getDir.*/Collection entries = repository.getDir(path, version, null,(Collection) null);Iterator iterator = entries.iterator();while (iterator.hasNext()) {SVNDirEntry entry = (SVNDirEntry) iterator.next();System.out.println("/" + (path.equals("") ? "" : path + "/")+ entry.getName() + " (author: '" + entry.getAuthor()+ "'; revision: " + entry.getRevision() + "; date: " + entry.getDate() + ")");/** Checking up if the entry is a directory.*/if (entry.getKind() == SVNNodeKind.DIR) {listEntries(repository, (path.equals("")) ? entry.getName(): path + "/" + entry.getName());}}}
四、通过原子方法实现简单svn相应操作
// svn 工作目录private static String copyPath = "C:/modelFiles/copy/";// svn 仓库目录private static String reposPath= "C:/modelFiles/repos/";// 临时文件存放目录private static String tmpPath= "C:/modelFiles/tmp/";// 初始提交本地copyPath下文件夹到svn仓库public static long commitFile(String dirName) throws SVNException {File sourcePath = new File(copyPath+dirName);SVNURL targetURL = SVNURL.parseURIEncoded("file:///"+reposPath+dirName);committedRevision = importDirectory(sourcePath, targetURL, "上传模型文件夹 "+dirName, true).getNewRevision();return committedRevision;}// 检出指定版本到指定目录// 其中 SVNRevision 为版本对象,可以通过SVNRevision.create(1) 形式创建版本id为1的版本对象// svn版本从1开始往后迭代,为长整型,0表示最新版本用 SVNRevision.HEAD表示,其等同于 SVNRevision.create(0)public static void checkOut(String dirName,String basePath,SVNRevision svnRevision) throws SVNException {SVNURL repository = SVNURL.parseURIEncoded("file:///"+reposPath);File wcDir = new File(basePath+"/"+dirName);checkout(repository.appendPath(dirName,false), svnRevision, wcDir, true);}// svn工作目录下新增文件夹或文件后提交至svn仓库public static long commitNewFile(String dirName,String newDir) throws SVNException {// svn工作区目录File wcDir = new File(copyPath+dirName);// svn工作目录下新增的文件夹File NewDir = new File(copyPath+newDir);// 为了防止当前不是最新版本先从svn仓库更新下最新代码,其实也可以不进行这一步操作update(wcDir, SVNRevision.HEAD, true);// 将当前新增的目录加入版本控制addEntry(NewDir);// 提交至svn仓库long newRevision = commit(wcDir, false,"在 " + dirName + " 目录下新增 " + newDir).getNewRevision();log.info("在 "+dirName+" 目录下新增 "+newDir);return newRevision;}// 删除svn工作目录下某个文件夹并提交svn仓库public static long deleteFile(String dirName,String delDir) throws SVNException {File wcDir = new File(copyPath+dirName);File DelDir = new File(copyPath+delDir);delete(DelDir, false);long newRevision = commit(wcDir, false,"从 " + dirName + " 目录下删除 " + delDir).getNewRevision();log.info("从 "+dirName+" 目录下删除 "+delDir);//删除后更新下update(wcDir, SVNRevision.HEAD, true);return newRevision;}// svn删除整个工作目录操作public static void deleteFileFromRepos(String dirName){try {SVNRepository svnRepository = FSRepositoryFactory.create(SVNURL.parseURIEncoded("file:///" + reposPath));ISVNEditor editor = svnRepository.getCommitEditor( "删除目录 "+dirName , null );try {deleteDir(editor, dirName);} catch ( SVNException svne ) {editor.abortEdit( );throw svne;}} catch (Exception e) {e.printStackTrace();}}/*** @description 创建指定版本的分支*/public static Long createBranchByCopy(String dirName,Long revisionNum) {try {SVNURL srcURL = SVNURL.parseURIEncoded("file:///"+reposPath+dirName);SVNURL dstURL = SVNURL.parseURIEncoded("file:///"+reposPath+dirName+"-分支");SVNCommitInfo copyInfo = copy(srcURL,dstURL,SVNRevision.create(revisionNum),true," 创建分支:" + dirName+"-分支");checkOut(getBranchName(dirName+"-分支",copyPath);return copyInfo.getNewRevision();} catch (SVNException e) {log.info("创建分支失败:"+e.getMessage());throw new RuntimeException(e);}}// 获取当前模型仓库的最新版本编号public static long getLatestRevision() throws SVNException {SVNRepository svnRepository = FSRepositoryFactory.create(SVNURL.parseURIEncoded("file:///" + reposPath));return svnRepository.getLatestRevision();}
相关文章:

java中使用svnkit实现文件的版本管理
java中使用svnkit实现文件的版本管理 一、引入svnKit依赖二、初始化仓库工厂类二、使用svnkit创建本地存储仓库三、svn基本原子操作四、通过原子方法实现简单svn相应操作 一、引入svnKit依赖 <dependency><groupId>org.tmatesoft.svnkit</groupId><artifa…...

了解 Linux 网络卡绑定:提高网络性能与冗余性
在现代 IT 基础设施中,网络性能和可靠性至关重要。对于许多企业和个人用户来说,确保网络的高可用性和冗余性是首要任务之一。Linux 提供了一个强大的解决方案——网络卡绑定(Network Interface Card Bonding,简称 NIC Bonding&…...

2024年618购物狂欢节即将来袭!精选五款超值入手数码好物!
618购物狂欢盛宴即将落幕,是时候展现我们的购物智慧了!在追求价格优惠的同时,我们更应看重商品的品质与实用性。面对琳琅满目的选择,如何筛选出真正值得拥有的好物呢?为了让大家的购物之旅更加轻松愉快,以下…...
中国AI独角兽资本大冒险
成立不过一年多时间,月之暗面已然成为中国大模型赛道上,最炙手可热的明星公司。 5月21日,华尔街见闻获悉,月之暗面将按照投前估值30亿美元(合217.3亿人民币)进行融资,完成后依然会是当前中国估…...

项目十二:简单的python基础爬虫训练
许久未见,甚是想念,今日好运,为你带好运。ok,废话不多说,希望这门案例能带你直接快速了解并运用。🎁💖 基础流程 第一步:安装需要用到的requests库,命令如下 pip inst…...
OpenGL学习入门及开发环境搭建
最近学习OpenGL开发,被各种openGL库搞得晕头转向,什么glut, glew glfw glad等等。 可以参考这边博客:OpenGL 下面的 glut freeglut glfw 都是个啥_glx wgl的中文-CSDN博客 glfw是glut的升级版,跨平台的主要处理窗口 事件相关。 glad是glew…...

three.js能实现啥效果?看过来,这里都是它的菜(08)
在Three.js中实现旋转动画的原理是通过修改对象的旋转属性来实现的,通常使用渲染循环(render loop)来更新对象的旋转状态,从而实现动画效果。 具体的原理包括以下几个步骤: 创建对象:首先创建一个需要旋转…...
SpringBoot(九)之整合mybatis
SpringBoot(九)之整合mybatis 文章目录 SpringBoot(九)之整合mybatisSpring整合mybatis回顾1. 引入依赖2. mybatis-config.xml SpringBoot整合mybatis1.引入依赖2. 配置数据源和 MyBatis 属性3. 配置 Mapper 接口4. 配置mapper.xm…...

【实战教程】使用Spring AOP和自定义注解监控接口调用
一、背景 随着项目的长期运行和迭代,积累的功能日益繁多,但并非所有功能都能得到用户的频繁使用或实际上根本无人问津。 为了提高系统性能和代码质量,我们往往需要对那些不常用的功能进行下线处理。 那么,该下线哪些功能呢&…...
算法学习之:Raft-分布式一致性/共识算法
基础介绍 Raft是什么? Raft is a consensus algorithm that is designed to be easy to understand. Its equivalent to Paxos in fault-tolerance and performance. The difference is that its decomposed into relatively independent subproblems, and it clea…...

彩色进度条(C语言版本)
.h文件 #include<stdio.h> #include<windows.h>#define NUM 101 #define LOAD_UP 50 #define LOAD_DOWN 60 #define SLEEP_SLOW 300 #define SLEEP_FAST 70 版本1:(初始版) //v1 #include "progress.h" int main() …...
C#和C++有什么区别?
C#和C都是广泛使用的编程语言,但它们在设计理念、应用场景和语法上有许多显著的区别。以下是一些关键区别的详细介绍: 1. 设计理念和目的 C: 设计目的:C是一种面向系统编程和应用程序开发的语言,具有高效性和灵活性…...

微信小程序报错:notifyBLECharacteristicValueChange:fail:nodescriptor的解决办法
文章目录 一、发现问题二、分析问题二、解决问题 一、发现问题 微信小程序报错:notifyBLECharacteristicValueChange:fail:nodescriptor 二、分析问题 这个提示有点问题,应该是该Characteristic的Descriptor有问题,而不能说nodescriptor。 …...
富格林:可信攻略阻止遭遇欺诈
富格林悉知,在投资市场中,如何阻止遭遇欺诈情况应该是每位投资者都想要了解的一个知识点。事实上,现货黄金市场相对来说会其他市场复杂多变,因此要想盈利出金还是得要先学会阻止遭遇欺诈情况。据富格林所知,目前市面上…...

搭建淘宝扭蛋机小程序:技术选型与最佳实践
随着移动互联网的快速发展,小程序作为一种轻量级应用,以其无需安装、即用即走的特点,受到了广大用户的喜爱。在电商领域,淘宝作为国内最大的电商平台之一,也积极拥抱小程序技术,为用户提供更加便捷、个性化…...

【线性回归】梯度下降
文章目录 [toc]数据数据集实际值估计值 梯度下降算法估计误差代价函数学习率参数更新 Python实现导包数据预处理迭代过程结果可视化完整代码 结果可视化线性拟合结果代价变化 数据 数据集 ( x ( i ) , y ( i ) ) , i 1 , 2 , ⋯ , m \left(x^{(i)} , y^{(i)}\right) , i 1 ,…...

GMSL图像采集卡,适用于无人车、自动驾驶、自主机器、数据采集等场景,支持定制
基于各种 系列二代 G MS L 图像采集卡(以下简称 二代图像采集卡)是一款自主研发的一款基于 F P G A 的高速图像产品,二代图像采集卡相比一代卡,由于采用PCIe G en 3 技术,速度和带宽都相应的有了成 倍的提高。该图像…...

docker不删除容器更改其挂载目录
场景:docker搭建的jenkins通常需要配置很多开发环境,当要更换挂载目录,每次都需要删除容器重新运行,不在挂载目录的环境通常不会保留。 先给一个参考博客docker不删除容器,修改容器挂载或其他_jenkins 修改容器挂载do…...

K8s Service 背后是怎么工作的?
kube-proxy 是 Kubernetes 集群中负责服务发现和负载均衡的组件之一。它是一个网络代理,运行在每个节点上, 用于 service 资源的负载均衡。它有两种模式:iptables 和 ipvs。 iptables iptables 是 Linux 系统中的一个用户空间实用程序,用于…...

ClickHouse配置与使用
静态IP配置 # 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33# 修改文件内容 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic IPADDR192.168.18.128 NETMASK255.255.255.0 GATEWAY192.168.18.2 DEFROUTEyes IPV4_FAILURE_FATALno IPV6INIT…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...