如果你想在一个 Java 程序中使用 Git ,有一个功能齐全的 Git 库,那就是 JGit 。 JGit 是一个用 Java 写成的功能相对健全的 Git 的实现,它在 Java 社区中被广泛使用。 JGit 项目由 Eclipse 维护,它的主页

依赖添加

有很多种方式可以将 JGit 依赖加入到你的项目,并依靠它去写代码。 最简单的方式也许就是使用 Maven 。你可以通过在你的 pom.xml 文件里的 标签中增加像下面这样的片段来完成这个整合。

    <dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>5.5.1.201910021850-r</version>
</dependency>

在你读到这段文字时 version 很可能已经更新了,所以请浏览 http://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit 以获取最新的仓库信息。 当这一步完成之后, Maven 就会自动获取并使用你所需要的 JGit 库。

项目实践

在搭建我的博客的过程中,因为该博客是部署在自己的服务器上,需要在ci自动编译完成后,实现自动部署到我的服务器上(该步实现的方式很多,通过开放git接口,有编译部署的时候自动拉取到我的服务器就是其中的一个方法)

以下主要使用了pull拉取方法

package com.easy.jGit.controller;

import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Repository;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.io.File; @RestController
@Slf4j
public class JGitController { /**
* git仓路径
*/
final String patch = "/opt/webapps/blog/.git"; /**
* 代码分支
*/
final String branch = "origin/gh-pages"; /**
* 拉取
*
* @return
*/
@RequestMapping("/pull")
public String pull() {
String result;
Repository repo = null;
try {
repo = new FileRepository(new File(patch));
Git git = new Git(repo); log.info("开始重置");
//重置
git.reset()
.setMode(ResetCommand.ResetType.HARD)
.setRef(branch).call(); log.info("开始拉取"); //拉取
git.pull()
.setRemote("origin")
.setRemoteBranchName("gh-pages")
.call();
result = "拉取成功!";
log.info(result);
} catch (Exception e) {
result = e.getMessage();
} finally {
if (repo != null) {
repo.close();
}
}
return result;
} /**
* 重置
*
* @return
*/
@RequestMapping("/reset")
public String reset() {
String result; Repository repo = null;
try {
repo = new FileRepository(new File(patch));
Git git = new Git(repo);
git.reset().setMode(ResetCommand.ResetType.HARD).setRef(branch).call();
result = "重置成功!"; } catch (Exception e) {
result = e.getMessage();
} finally {
if (repo != null) {
repo.close();
}
}
return result;
} /**
* 恢复
*/
@RequestMapping("/revert")
public String revert() {
String result; Repository repo = null;
try {
repo = new FileRepository(new File(patch));
Git git = new Git(repo);
git.revert().call();
result = "恢复成功!"; } catch (Exception e) {
result = e.getMessage();
} finally {
if (repo != null) {
repo.close();
}
}
return result;
} /**
* 克隆
*
* @return
*/
@RequestMapping("/clone")
public String clone() {
String result;
try {
Git.cloneRepository()
.setURI("https://github.com/smltq/blog.git")
.setDirectory(new File("/blog"))
.call();
result = "克隆成功了!";
} catch (GitAPIException e) {
result = e.getMessage();
e.printStackTrace();
}
return result;
} /**
* 状态
*/
@RequestMapping("/status")
public static void status() {
File RepoGitDir = new File("/blog/.git");
Repository repo = null;
try {
repo = new FileRepository(RepoGitDir.getAbsolutePath());
Git git = new Git(repo);
Status status = git.status().call();
log.info("Git Change: " + status.getChanged());
log.info("Git Modified: " + status.getModified());
log.info("Git UncommittedChanges: " + status.getUncommittedChanges());
log.info("Git Untracked: " + status.getUntracked());
} catch (Exception e) {
log.info(e.getMessage());
} finally {
if (repo != null) {
repo.close();
}
}
}
}

.travis.yml 源文件

language: node_js # 设置语言
node_js: stable # 设置相应版本
cache:
apt: true
directories:
- node_modules # 缓存不经常更改的内容
before_install:
- export TZ='Asia/Shanghai' # 更改时区
- npm install hexo-cli -g
#- chmod +x ./publish-to-gh-pages.sh # 为shell文件添加可执行权限
install:
- npm install # 安装hexo及插件
script:
- hexo clean # 清除
- hexo g # 生成
after_script:
- git clone https://${GH_REF} .deploy_git
- cd .deploy_git
- git checkout master:gh-pages
- cd ../
- mv .deploy_git/.git/ ./public/
- cd ./public
- git config user.name "tqlin"
- git config user.email "smltq@126.com"
# add commit timestamp
- git add .
- git commit -m "Travis CI Auto Builder at `date +"%Y-%m-%d %H:%M"`"
- git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" master:gh-pages && curl http://49.235.170.100:8787/pull
- curl http://49.235.170.100:8787/pull #这里调用上面实现的拉取接口
branches:
only:
- master # 只监测master分支
env:
global:
- GH_REF: github.com/smltq/blog.git #设置GH_REF

基本概念

  • Repository 包括所有的对象和引用,用来管理源码

  • AnyObjectId 表示SHA1对象,可以获得SHA1的值,进而可以获得git对象

  • Ref 引用对象,表示.git/refs下面的文件引用 Ref HEAD = repository.getRef("refs/heads/master");

  • RevWalk 可以遍历提交对象,并按照顺序返回提交对象

  • RevCommit 代表一个提交对象

  • RevTag 代表标签对象

  • RevTree 代表树对象

其它常用命令

大多数 JGit 会话会以 Repository 类作为起点,你首先要做的事就是创建一个它的实例。 对于一个基于文件系统的仓库来说(JGit 允许其它的存储模型),用 FileRepositoryBuilder 完成它。

// 创建一个新仓库
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create(); // 打开一个存在的仓库
Repository existingRepo = new FileRepositoryBuilder()
.setGitDir(new File("my_repo/.git"))
.build();

当你拥有一个 Repository 实例后,你就能对它做各种各样的事。比如:

// 获取引用
Ref master = repo.getRef("master"); // 获取该引用所指向的对象
ObjectId masterTip = master.getObjectId(); // Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}"); // 装载对象原始内容
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out); // 创建分支
RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update(); // 删除分支
RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete(); // 配置
Config cfg = repo.getConfig();
String name = cfg.getString("user", null, "name");

提交命令

AddCommand可以把工作区的内容添加到暂存区。

Git git = Git.open(new File("D:\\source-code\\temp\\.git"));
git.add().addFilepattern(".").call(); // 相当与git add -A添加所有的变更文件git.add().addFilepattern("*.java")这种形式是不支持的
git.add().addFilepattern("src/main/java/").call(); // 添加目录,可以把目录下的文件都添加到暂存区
//jgit当前还不支持模式匹配的方式,例如*.java

CommitCommand用于提交操作

Git git =Git.open(new File("D:\\source-code\\temp\\user1\\.git"));
CommitCommand commitCommand = git.commit().setMessage("master 23 commit").setAllowEmpty(true);
commitCommand.call();

status命令

    Git git = Git.open(new File("D:\\source-code\\temp-1\\.git"));
Status status = git.status().call(); //返回的值都是相对工作区的路径,而不是绝对路径
status.getAdded().forEach(it -> System.out.println("Add File :" + it)); //git add命令后会看到变化
status.getRemoved().forEach(it -> System.out.println("Remove File :" + it)); ///git rm命令会看到变化,从暂存区删除的文件列表
status.getModified().forEach(it -> System.out.println("Modified File :" + it)); //修改的文件列表
status.getUntracked().forEach(it -> System.out.println("Untracked File :" + it)); //工作区新增的文件列表
status.getConflicting().forEach(it -> System.out.println("Conflicting File :" + it)); //冲突的文件列表
status.getMissing().forEach(it -> System.out.println("Missing File :" + it)); //工作区删除的文件列表

log命令

LogCommand相当于git log命令

//提取某个作者的提交,并打印相关信息
Git git = Git.open(new File("D:\\source-code\\temp-1\\.git"));
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Iterable<RevCommit> results = git.log().setRevFilter(new RevFilter() {
@Override
public boolean include(RevWalk walker, RevCommit cmit)
throws StopWalkException, MissingObjectException, IncorrectObjectTypeException, IOException {
return cmit.getAuthorIdent().getName().equals("xxxxx dsd");
} @Override
public RevFilter clone() {
return this;
}
}).call();
results.forEach(commit -> {
PersonIdent authoIdent = commit.getAuthorIdent();
System.out.println("提交人: " + authoIdent.getName() + " <" + authoIdent.getEmailAddress() + ">");
System.out.println("提交SHA1: " + commit.getId().name());
System.out.println("提交信息: " + commit.getShortMessage());
System.out.println("提交时间: " + format.format(authoIdent.getWhen()));
});

fetch命令

fetch命令

Repository rep = new FileRepository("D:\\source-code\\temp-1\\.git");
Git git = new Git(rep);
git.pull().setRemote("origin").call();
//fetch命令提供了setRefSpecs方法,而pull命令并没有提供,所有pull命令只能fetch所有的分支
git.fetch().setRefSpecs("refs/heads/*:refs/heads/*").call();

push命令

而PushCommand和git push相同,一般都需要我们提供用户名和密码,需要用到CredentialsProvider类

Repository rep = new FileRepository("D:\\source-code\\temp-1\\.git");
Git git = new Git(rep);
git.push().setCredentialsProvider(new UsernamePasswordCredentialsProvider("myname", "password")).call();

clone命令

CloneCommand等价与git clone命令

Git.cloneRepository().setURI("https://admin@localhost:8443/r/game-of-life.git")
.setDirectory(new File("D:\\source-code\\temp-1")).call();

RevWalk API

以下代码实现这样一个功能,查找某个文件的历史记录,并把每个提交的文件内容打印出来。

 DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Repository repository = new RepositoryBuilder().setGitDir(new File("D:\\source-code\\temp-1\\.git")).build();
try (RevWalk walk = new RevWalk(repository)) {
Ref head = repository.findRef("HEAD");
walk.markStart(walk.parseCommit(head.getObjectId())); // 从HEAD开始遍历,
for (RevCommit commit : walk) {
RevTree tree = commit.getTree(); TreeWalk treeWalk = new TreeWalk(repository, repository.newObjectReader());
PathFilter f = PathFilter.create("pom.xml");
treeWalk.setFilter(f);
treeWalk.reset(tree);
treeWalk.setRecursive(false);
while (treeWalk.next()) {
PersonIdent authoIdent = commit.getAuthorIdent();
System.out.println("提交人: " + authoIdent.getName() + " <" + authoIdent.getEmailAddress() + ">");
System.out.println("提交SHA1: " + commit.getId().name());
System.out.println("提交信息: " + commit.getShortMessage());
System.out.println("提交时间: " + format.format(authoIdent.getWhen())); ObjectId objectId = treeWalk.getObjectId(0);
ObjectLoader loader = repository.open(objectId);
loader.copyTo(System.out); //提取blob对象的内容
}
}
}

其它更多命令参考官网

资料

Spring Boot、Cloud 学习项目

JGit----将 Git 嵌入你的应用的更多相关文章

  1. JAVA 使用jgit管理git仓库

    最近设计基于gitops新的CICD方案,需要通过java读写git仓库,这里简单记录下. JGit是一款pure java的软件包,可以读写git仓库,下面介绍基本使用. 引入jgit maven引 ...

  2. Git中文版教程

    1. 起步 1.1 关于版本控制 1.2 Git 简史 1.3 Git 基础 1.4 命令行 1.5 安装 Git 1.6 初次运行 Git 前的配置 1.7 获取帮助 1.8 总结 2. Git 基 ...

  3. Git Pro Book

    目录 2nd Edition (2014) Switch to 1st Edition Download Ebook The entire Pro Git book, written by Scott ...

  4. java操作git简单实现

    记录瞬间 import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ListBranchCommand; import org.ecli ...

  5. 如何在Ubuntu 16.04安装的Git【转】

    转自:https://www.howtoing.com/how-to-install-git-on-ubuntu-16-04/ 介绍 现代软件开发中不可或缺的工具是某种版本控制系统. 版本控制系统允许 ...

  6. 通过jgit一次性升级fastjson版本

    背景:笔者所在公司经历了三次fastjson的升级,由于集群,工程数量众多,每次升级都很麻烦.因此开发了一个java的升级工具. 功能介绍: 功能介绍:一个jar文件,通过java -jar命令,输入 ...

  7. JGit、SvnKit - 版本提交日志(1)提取

    1.相关开源jar包  1>使用JGIT访问git项目  2>使用SVNkit访问svn Git官方JGit使用教程指导 2.Git历史提交日志导出到文件 在项目根目录执行如下命令,将日志 ...

  8. 探讨 Git 代码托管平台的若干问题

    关于 Git 版本控制软件种类繁多,维基百科收录的最早的版本控制系统是 1972 年贝尔实验室开发的 Source Code Control System.1986 年 Concurrent Vers ...

  9. 探讨 Git 代码托管平台的若干问题 - 2019 版

    关于 Git 版本控制软件种类繁多,维基百科收录的最早的版本控制系统是 1972 年贝尔实验室开发的 Source Code Control System.1986 年 Concurrent Vers ...

随机推荐

  1. 通俗易懂了解Vue的计算属性

    1.前言 之前在学习vue的过程中,一直没有搞明白计算属性是个怎么回事,以及为什么要有计算属性,使用计算属性有什么好处.今天花时间翻了翻官方文档,才搞清楚其中一二,现将学习心得总结记录如下. 2.为什 ...

  2. P3521 [POI2011]ROT-Tree Rotations(线段树合并)

    一句话题意(不用我改了.....):给一棵n(1≤n≤200000个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少. ......这题输入很神烦呐... 给你一棵二叉树的dfs序 ...

  3. 关于一个 websocket 多节点分布式问题的头条面试题

    原文链接,欢迎讨论: [Q023]websocket 服务多节点部署时会有什么问题,怎么解决 你来说说 websocket 有什么用 双向通信,服务器端可以主动 push,给客户端发送通知 那webs ...

  4. 分类算法之逻辑回归(Logistic Regression

    分类算法之逻辑回归(Logistic Regression) 1.二分类问题 现在有一家医院,想要对病人的病情进行分析,其中有一项就是关于良性\恶性肿瘤的判断,现在有一批数据集是关于肿瘤大小的,任务就 ...

  5. Git如何fork别人的仓库并作为贡献者提交代码

    例如 要fork一份google的MLperf/inference代码,下面介绍具体做法:预备知识git里的参考有几种表示,分别是上游仓库,远程仓库和本地仓库,逻辑关系如下拉取代码的顺序:别的大牛的代 ...

  6. aop的简单使用(代码和配置记录)

    Spring aop 简单示例 简单的记录一下spring aop的一个示例 基于两种配置方式: 基于xml配置 基于注解配置 这个例子是模拟对数据库的更改操作添加事物 其实并没有添加,只是简单的输出 ...

  7. Python连接SqlServer+GUI嵌入式——学生管理系统1.0

    学生管理系统1.0 1.建学生数据库 2.数据库嵌入高级语言(Python) 3.界面设计 简化思路: 1.先通过SqlServer2012建立学生数据库,包括账号.密码,姓名.选课等信息 2.运用P ...

  8. nyoj 20-吝啬的国度 (DFS)

    20-吝啬的国度 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:12 submit:43 题目描述: 在一个吝啬的国度里有N个城市,这N个城市间只有 ...

  9. 【SSM Spring 线程池 OJ】 使用Spring线程池ThreadPoolTaskExecutor

    最近做的Online Judge项目,在本地判题的实现过程中,遇到了一些问题,包括多线程,http通信等等.现在完整记录如下: OJ有一个业务是: 用户在前端敲好代码,按下提交按钮发送一个判题请求给后 ...

  10. android灭屏后调用binder通讯竟然影响了socket的POLL_OUT事件,怪事。

    当你的android在灭屏(休眠)时分派(dispatch) Ice调用过程中,如果创建了新的进程,你的响应将不会预期那样工作,尽管你已经调用 ice_response或 ice_exception, ...