JGit 在java中操作Git仓库
jgit是eclipse基金会下属的一个java项目,用于在java环境下实现对git仓库的操作,包括的基本的clone pull push remote commit add等操作。当然底层的实现逻辑还是依赖了操作系统中已安装的Git软件。
在jgit中存在一个抽象类FS
实现了基本的和Git程序的交互,派生出三个实现类FS_POSIX
FS_Win32
FS_Win32_Cygwin
分别应对三种不同的git环境。其中FS_Win32 是比较常见的环境,此类实现了runInShell
方法,从中可以明确的知道jgit是直接通过sh调用了git。windows版本的git其实是linux移植版本,算不上纯正windows,自带了mingw64环境用于模拟linux环境。sh.exe就是这个环境下的shell。
public ProcessBuilder runInShell(String cmd, String[] args) { Listargv = new ArrayList<>(4 + args.length); argv.add("sh.exe"); //$NON-NLS-1$ argv.add("-c"); //$NON-NLS-1$ argv.add(cmd + " \"$@\""); //$NON-NLS-1$ argv.add(cmd); argv.addAll(Arrays.asList(args)); ProcessBuilder proc = new ProcessBuilder(); proc.command(argv); return proc; }
在jgit中,存在最核心的三个组件:Git类,Repository类。Git类中包含了push commit之类的常见git操作,而Repository则实现了仓库的初始化和基本的管理功能。
Git类的实例都会持有一个Repository实例。
Repository类的初始化
针对一个git仓库,我们一般会有三种方式获得
1.新建一个空仓库
Git git = Git.init().setDirectory(localPath).call()
2.加载一个已存在的仓库
Repository repository = builder.setGitDir(repoDir) .readEnvironment() // scan environment GIT_* variables .findGitDir() // scan up the file system tree .build()
3.从远程仓库下载
Git result = Git.cloneRepository() .setURI(REMOTE_URL) .setDirectory(localPath) .call()
接下来贴一个完整的git工具类 GitRepository
package cn.bobmao.pro.logic.utils; import cn.bobmao.pro.logic.config.Const; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import org.apache.commons.io.FileUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.TransportConfigCallback; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.transport.JschConfigSessionFactory; import org.eclipse.jgit.transport.OpenSshConfig; import org.eclipse.jgit.transport.SshTransport; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.util.FS; import org.jetbrains.annotations.NotNull; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; // 实现了Closeable接口,使用的时候记得卸载try()中 仓库使用完毕或者代码出错后必须close public class GitRepository implements Closeable { private Git targetRepo; private Git sourceRepo; private TransportConfigCallback targetSessionFactory; // 1. 下载或者更新sourceRepo // 2. 下载或者更新targetRepo 然后删掉targetRepo里的东西 把sourceRepo里的东西复制到targetRepo public void init() throws IOException, GitAPIException, URISyntaxException { // TransportConfigCallback这个东西 是因为使用ssh连接服务器 存在一个key不受信任的问题 // 具体搜索关键词StrictHostKeyChecking 这里只是封装了构建代码 TransportConfigCallback sourceSessionFactory = getTransportConfigCallback(Const.getGitPrivateKey()); targetSessionFactory = getTransportConfigCallback(Const.getGitTargetPrivateKey()); sourceRepo = cloneRepo(Const.getSourcePath(), Const.getRemoteSourceUrl(), sourceSessionFactory); targetRepo = cloneRepo(Const.getTargetPath(), Const.getRemoteTargetUrl(), targetSessionFactory); // 清空生成的代码 FileUtils.deleteDirectory(new File(Const.getTargetPath() + File.separator + Const.getProjectDirName())); // 复制模板代码到生成代码目录 FileUtils.copyDirectory(new File(Const.getSourcePath() + File.separator + Const.getProjectDirName()), new File(Const.getTargetPath() + File.separator + Const.getProjectDirName())); } @NotNull private TransportConfigCallback getTransportConfigCallback(String sshKey) { JschConfigSessionFactory jschConfigSessionFactory = new JschConfigSessionFactory() { @Override protected void configure(OpenSshConfig.Host host, Session session) { session.setConfig("StrictHostKeyChecking", "no"); } @Override protected JSch createDefaultJSch(FS fs) throws JSchException { JSch defaultJSch = super.createDefaultJSch(fs); // 配置 ssh key defaultJSch.addIdentity(sshKey); return defaultJSch; } }; return transport -> { SshTransport sshTransport = (SshTransport) transport; sshTransport.setSshSessionFactory(jschConfigSessionFactory); }; } public void commitAndPush(String version) throws GitAPIException { commitAll(); tag(version); push(); } /** * 初始化代码仓库 */ public Git cloneRepo(String targetPath, String url, TransportConfigCallback sshSessionFactory) throws GitAPIException, IOException, URISyntaxException { File file = new File(targetPath); Git git; if (file.exists()) { FileRepositoryBuilder builder = new FileRepositoryBuilder(); Repository repository = builder.setGitDir(new File(targetPath + File.separator + ".git")) .readEnvironment() .findGitDir() .build(); git = new Git(repository); git.remoteSetUrl().setRemoteUri(new URIish(url)).setRemoteName("origin").call(); git.pull().setTransportConfigCallback(sshSessionFactory).call(); } else { git = Git.cloneRepository() .setURI(url) .setBranch("dev") .setDirectory(file) .setTransportConfigCallback(sshSessionFactory).call(); } return git; } public void commitAll() throws GitAPIException { targetRepo.add().addFilepattern(".").call(); targetRepo.commit() .setAll(true) .setMessage("Generate Code") .call(); } public void push() throws GitAPIException { // 推送代码 targetRepo.push().setTransportConfigCallback(targetSessionFactory).call(); // 推送tag targetRepo.push().setTransportConfigCallback(targetSessionFactory).setPushTags().call(); } public void tag(String version) throws GitAPIException { targetRepo.tag().setName(version).call(); } @Override public void close() { if (sourceRepo != null) { // 如果不close 下次操作会直接报错 因为仓库已被占用 sourceRepo.close(); } if (targetRepo != null) { targetRepo.close(); } } }
大部分的jgit功能可以使用在cookbook上查找到
https://github.com/centic9/jgit-cookbook