如果你想在一個 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();
}
}
}
}
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對象的內容
}
}
}
其它更多命令參考官網