java 操作git
实现功能:借助jgit实现拉取文件,并返回文件路径清单
<!-- 依赖库 版本号有自行选择,只是需要注意支持的jdk版本即可,我使用的是jdk1.8-->
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>5.13.2.202306221912-r</version>
</dependency>
// 还是用的 hutool和 lombok ,没有引入相关依赖的可以删除相关代码,使用类似代码替代。
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PullResult;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class GitUtil {
/**
* 克隆git库.
* @param url
* @param localPath
*/
public static void cloneRepository(String url, String localPath) {
try {
Git git = Git.cloneRepository()
.setURI(url)
.setDirectory(new File(localPath))
.call();
Repository repository = git.getRepository();
repository.close();
log.info("Cloned repository successfully from {} to {}", url, localPath);
} catch (GitAPIException e) {
log.error("Failed to clone repository from {} to {}", url, localPath, e);
} catch (Exception e) {
log.error("Failed to clone repository from {} to {}", url, localPath, e);
}
}
/**
* 初始化本地git库.
* @param localPath
*/
public static void initRepository(String localPath) {
try {
Git git = Git.init()
.setDirectory(new File(localPath))
.call();
Repository repository = git.getRepository();
repository.close();
log.info("Initialized repository successfully at {}", localPath);
} catch (GitAPIException e) {
log.error("Failed to initialize repository at {}", localPath, e);
} catch (Exception e) {
log.error("Failed to initialize repository at {}", localPath, e);
}
}
/**
* 添加
* @param git
*/
public static void addAll(Git git) {
try {
git.add().addFilepattern(".").call();
log.info("Added all files to staging area");
} catch (GitAPIException e) {
log.error("Failed to add all files to staging area", e);
} catch (Exception e) {
log.error("Failed to add all files to staging area", e);
}
}
/**
* 提交
* @param git
* @param message
*/
public static void commit(Git git, String message) {
try {
git.commit().setMessage(message).call();
log.info("Committed changes with message: {}", message);
} catch (GitAPIException e) {
log.error("Failed to commit changes with message: {}", message, e);
} catch (Exception e) {
log.error("Failed to commit changes with message: {}", message, e);
}
}
/**
* 依据本地目录获取本地git库
* @param localPath
* @return
*/
public static Repository getRepository(String localPath) {
FileRepositoryBuilder builder = new FileRepositoryBuilder();
try {
return builder.setGitDir(new File(localPath + "/.git"))
.readEnvironment()
.findGitDir()
.build();
} catch (Exception e) {
log.error("Failed to open repository at {}", localPath, e);
return null;
}
}
private static CanonicalTreeParser getTreeByObjectId(Git git, ObjectId objectId) throws Exception {
try (ObjectReader reader = git.getRepository().newObjectReader();) {
CanonicalTreeParser treeIter = new CanonicalTreeParser();
treeIter.reset(reader, objectId);
return treeIter;
}
}
private static String getChangeType(DiffEntry diffEntry) {
if (StrUtil.equals("/dev/null", diffEntry.getNewPath())) {
return "del";
}
if (StrUtil.equals("/dev/null", diffEntry.getOldPath())) {
return "add";
}
return "update";
}
private static void addDiifToMap(@NotNull Map<String, List<String>> changeInfoMap, @NotNull DiffEntry diffEntry) {
String changeType = getChangeType(diffEntry);
List<String> fileNameList = changeInfoMap.get(changeType);
if (fileNameList == null) {
changeInfoMap.put(changeType, new ArrayList<>());
fileNameList = changeInfoMap.get(changeType);
}
fileNameList.add(StrUtil.equals("del", changeType) ? diffEntry.getOldPath() : diffEntry.getNewPath());
}
/**
* 拉取文件并返回拉取的文件清单
* @param repository
* @return 返回 del(删除)、add(新增)、update(更新)的文件清单
*/
public static Map<String, List<String>> pull(Repository repository) {
Map<String, List<String>> changeInfoMap = new HashMap<>();
try (Git git = new Git(repository);) {
// 1.拉取前记录当前的版本号.
FetchResult fetchResult = git.fetch().call();
ObjectId oldHead = git.getRepository().resolve("HEAD^{tree}");
// 2.拉取并记录拉取后的版本号
PullResult result = git.pull().call();
ObjectId newHead = git.getRepository().resolve("HEAD^{tree}");
// 3.计算差异清单。
List<DiffEntry> diffs = git.diff()
.setNewTree(getTreeByObjectId(git, newHead))
.setOldTree(getTreeByObjectId(git, oldHead))
.call();
for (DiffEntry entry : diffs) {
addDiifToMap(changeInfoMap,entry);
}
} catch (GitAPIException e) {
log.error("Failed to pull changes from remote repository", e);
} catch (Exception e) {
log.error("Failed to pull changes from remote repository", e);
}
return changeInfoMap;
}
}
使用方式:
1. 在将代码库拉取到本地的目录中(也可以通过上面的代码,直接从远程仓库克隆到本地目录中)
2. 使用pull方法即可针对指定目录的git库进行拉取并返回拉取的文件清单,以做其他用处。
以上仅为案例,实际功能还需要配合其他逻辑实现。