欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

JGit 的 Java 操作 Git

最编程 2024-03-09 21:23:48
...

Java操作Git之JGit

博文地址:https://www.cnblogs.com/imchentiefeng/articles/java-git-jgit.html

git地址:Java操作Git之JGit.md

背景

​ 最近在做的项目中,有需求需要向git仓库上传文件,于是考虑到了在项目中通过Java代码来操作git仓库,记得以前自己搭建过Gitblit环境,它是一个开源的、基于Java编写的Git服务端,于是下载了Gitblit的源码,看到是基于JGit进行的封装,于是通过查看源码,加上参考JGit API 在线官方文档以及JGit Cookbook,编写了一个供自己使用的工具类,现分享给大家。

开始

1、引入依赖

我这里使用的Maven环境,引入依赖如下:

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

2、git分支类型

考虑到仓库分为本地仓库和远端仓库,我创建了一个枚举帮助后面的工具类中使用,如下:

import lombok.Getter;

/**
 * git分支类型
 *
 * @author chentiefeng
 * @date 2021/2/10 15:03
 */
@Getter
public enum GitBranchType {
    /**
     * 本地分支
     */
    LOCAL("refs/heads/"),
    /**
     * 远程分支
     */
    REMOTE("refs/remotes/origin/");
    /**
     * 分支前缀
     */
    private String prefix;
    GitBranchType(String prefix) {
        this.prefix = prefix;
    }
}

3、工具类

工具类内容如下:

import com.chen.common.git.enums.GitBranchType;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Git工具类
 * 更多jgit的操作,请看:
 *  官方文档:http://archive.eclipse.org/jgit/site/3.7.0.201502260915-r/index.html
 *  示例代码:https://github.com/centic9/jgit-cookbook
 * @author chentiefeng
 * @date 2021/2/10 14:02
 */
@Slf4j
public class GitUtils {
    
    /**
     * 提交文件到仓库 (包括新增的、更改的、删除的)
     * @param git
     * @param credential
     * @param filePattern
     * @param commitMessage
     * @return
     * @throws GitAPIException
     * @throws IOException
     */
    public static boolean commitFiles(Git git, CredentialsProvider credential, String filePattern, String commitMessage) throws GitAPIException, IOException {
        //添加
        git.add().addFilepattern(filePattern).call();
        git.add().addFilepattern(filePattern).setUpdate(true).call();
        //提交
        git.commit().setMessage(commitMessage).call();
        //推送到远程
        Iterable<PushResult> pushResults = git.push().setCredentialsProvider(credential).call();
        printCommitPushResult(pushResults, git.getRepository().getBranch(), commitMessage);
        return true;
    }

    /**
     * 打印提交文件的日志
     * @param results
     */
    private static void printCommitPushResult(Iterable<PushResult> results, String branchName, String commitMessage) {
        log.info("git add && git commit -m '{}'", commitMessage);
        log.info("git push");
        for (PushResult result : results) {
            RemoteRefUpdate remoteRefUpdate  = result.getRemoteUpdate(GitBranchType.LOCAL.getPrefix() + branchName);
            if (Status.OK.equals(remoteRefUpdate.getStatus())) {
                log.info("remote: " + result.getMessages().substring(0, result.getMessages().length() - 1));
            } else {
                log.error("remote: " + result.getMessages());
            }
            log.info("To {}", result.getURI());
        }
    }
    /**
     * 删除分支
     * @param git
     * @param credential
     * @param branchName
     * @return
     * @throws GitAPIException
     * @throws IOException
     */
    public static boolean removeBranch(Git git, CredentialsProvider credential, String branchName) throws GitAPIException, IOException {
        // master分支不能删除
        if ("master".equals(branchName)) {
            return false;
        }

        String oldBranch = git.getRepository().getBranch();
        //如果要删除的分支等于当前分支,切换到master
        if (oldBranch.equals(branchName)) {
            git.checkout().setName("master").call();
        }
        git.branchDelete().setBranchNames(GitBranchType.LOCAL.getPrefix() + branchName).setForce(true).call();
        git.branchDelete().setBranchNames(GitBranchType.REMOTE.getPrefix() + branchName).setForce(true).call();
        //推送到远程
        String branchFullName = GitBranchType.LOCAL.getPrefix() + branchName;
        RefSpec refSpec = new RefSpec(":" + branchFullName).setForceUpdate(true);
        Iterable<PushResult> results =  git.push().setCredentialsProvider(credential).setRefSpecs(refSpec).call();
        printRemoveBranchResult(results, branchFullName, branchName);
        return true;
    }

    /**
     * 打印删除分支的日志
     * @param results
     * @param branchFullName
     */
    private static void printRemoveBranchResult(Iterable<PushResult> results, String branchFullName, String branchName) {
        log.info("git push origin --delete {}", branchName);
        for (PushResult result : results) {
            RemoteRefUpdate remoteRefUpdate  = result.getRemoteUpdate(branchFullName);
            if (Status.OK.equals(remoteRefUpdate.getStatus())) {
                log.info("remote: " + result.getMessages().substring(0, result.getMessages().length() - 1));
            } else {
                log.error("remote: " + result.getMessages());
            }
            log.info("To {}", result.getURI());
            log.info("- [deleted]    {}", branchName);
        }
    }
    /**
     * 创建分支
     * @param git
     * @param branchName
     * @return
     * @throws GitAPIException
     * @throws IOException
     */
    public static String createBranch(Git git, CredentialsProvider credential, String branchName) throws GitAPIException, IOException {
        //如果本地存在分支,直接返回
        if (getBranches(git, GitBranchType.LOCAL).contains(branchName)) {
            return branchName;
        }
        //如果远端存在分支,则创建本地分支
        if (getBranches(git, GitBranchType.REMOTE).contains(branchName)) {
            String oldBranch = git.getRepository().getBranch();
            git.checkout().setName(branchName).setCreateBranch(true).call();
            git.checkout().setName(oldBranch).call();
            return branchName;
        }
        //新建分支
        git.branchCreate().setName(branchName).call();
        String oldBranch = git.getRepository().getBranch();
        git.checkout().setName(branchName).call();
        //推送到远程
        git.push().setCredentialsProvider(credential).call();
        git.checkout().setName(oldBranch).call();
        return branchName;
    }

    /**
     * 获取所有分支
     * @param git
     * @param branchType 分支类型,分为本地分支和远程分支
     * @return
     * @throws GitAPIException
     * @throws IOException
     */
    public static List<String> getBranches(Git git, GitBranchType branchType) throws GitAPIException, IOException {
        if (GitBranchType.LOCAL.equals(branchType)) {
            List<Ref> refs = git.branchList().call();
            return refs.stream().map(ref -> ref.getName().substring(GitBranchType.LOCAL.getPrefix().length()))
                    .collect(Collectors.toList());
        } else {
            List<Ref> refs = git.getRepository().getRefDatabase().getRefs();
            return refs.stream().filter(item -> !(item instanceof SymbolicRef))
                    .filter(item -> item.getName().startsWith(GitBranchType.REMOTE.getPrefix()))
                    .map(ref -> ref.getName().substring(GitBranchType.REMOTE.getPrefix().length()))
                    .collect(Collectors.toList());
        }
    }

    /**
     * 获取git对象
     * @param gitUrl git的http路径
     * @param credentialsProvider 认证
     * @param localPath 本地路径
     * @return
     * @throws IOException
     * @throws GitAPIException
     */
    public static Git getGit(String gitUrl, CredentialsProvider credentialsProvider, String localPath) throws IOException, GitAPIException {
        if (new File(localPath).exists() ) {
            return Git.open(new File(localPath));
        } else {
            return Git.cloneRepository().setCredentialsProvider(credentialsProvider).setURI(gitUrl)
                    .setDirectory(new File(localPath)).call();
        }
    }

    /**
     * 关闭git
     * @param git
     */
    public static void closeGit(Git git) {
        git.close();
    }
    /**
     * 创建Git认证信息
     * @param username
     * @param password
     * @return
     */
    public static CredentialsProvider createCredentialsProvider(String username, String password) {
        return new UsernamePasswordCredentialsProvider(username, password);
    }

}

4、测试工具类

测试如下:

/**
 * Git工具类测试
 * @author chentiefeng
 * @date 2021/2/10 14:02
 */
public class GitUtilsTest {
    public static void main(String[] args) throws IOException, GitAPIException {
        String gitUrl = "https://gitee.com/smart-it-work/smart-stream.git";
        String username = "imchentiefeng@aliyun.com";
        String password = "********";
        String localDir = "D:\\test\\smart-stream";
        CredentialsProvider credential = GitUtils.createCredentialsProvider(username, password);
        Git git = GitUtils.getGit(gitUrl, credential, localDir);
        List<String> localBranches = GitUtils.getBranches(git, GitBranchType.LOCAL);
        List<String> remoteBranches = GitUtils.getBranches(git, GitBranchType.REMOTE);
        String test = GitUtils.createBranch(git, credential, "test");
        boolean flag = GitUtils.removeBranch(git, credential, "test");
        boolean commitFlag = GitUtils.commitFiles(git, credential, ".", "test");
        GitUtils.closeGit(git);
    }
}

推荐阅读