【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();

        // 生成 README
        File 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 安装

3、JGit 资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值