java中使用svnkit实现文件的版本管理

一、引入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();
    }
  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值