如何在Java程序中使用JGit列出修改指定目录的所有Git提交
使用JGit列出修改指定目录文件的所有提交
核心实现思路
通过JGit的RevWalk遍历仓库提交,对每个提交做以下检查:
- 若为初始提交(无父提交),直接遍历提交树中的所有文件,判断是否存在目标目录下的文件
- 若有父提交,对比当前提交与父提交的差异,检查变更文件的路径是否包含目标目录
完整代码示例
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevSort; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.io.DisabledOutputStream; import java.io.File; import java.util.List; public class GitCommitScanner { public static void main(String[] args) throws Exception { // 替换为你的仓库路径 String repoPath = "/path/to/your/repository"; // 替换为目标目录,注意末尾加斜杠确保匹配目录下的所有文件 String targetDir = "x/"; try (Git git = Git.open(new File(repoPath))) { Repository repo = git.getRepository(); try (RevWalk revWalk = new RevWalk(repo)) { // 从HEAD开始遍历所有提交 revWalk.markStart(revWalk.parseCommit(repo.resolve("HEAD"))); // 可选:设置为从旧到新排序,去掉此行则默认从新到旧 revWalk.sort(RevSort.REVERSE); for (RevCommit commit : revWalk) { boolean affectsTargetDir = false; // 处理初始提交(无父提交) if (commit.getParentCount() == 0) { try (TreeWalk treeWalk = new TreeWalk(repo)) { treeWalk.addTree(commit.getTree()); treeWalk.setRecursive(true); while (treeWalk.next()) { String filePath = treeWalk.getPathString(); if (filePath.startsWith(targetDir)) { affectsTargetDir = true; break; } } } } else { // 对比当前提交与第一个父提交的差异 RevCommit parentCommit = revWalk.parseCommit(commit.getParent(0).getId()); try (DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE)) { diffFormatter.setRepository(repo); List<DiffEntry> diffEntries = diffFormatter.scan(parentCommit.getTree(), commit.getTree()); for (DiffEntry entry : diffEntries) { String filePath = entry.getNewPath(); // 处理文件被删除的情况,此时需要检查旧路径 if (entry.getChangeType() == DiffEntry.ChangeType.DELETE) { filePath = entry.getOldPath(); } if (filePath.startsWith(targetDir)) { affectsTargetDir = true; break; } } } } if (affectsTargetDir) { // 输出符合条件的提交信息,可根据需求调整输出内容 System.out.printf("提交ID: %s | 提交时间: %tF %tT | 提交信息: %s%n", commit.getId().abbreviate(7).getName(), commit.getCommitterIdent().getWhen(), commit.getCommitterIdent().getWhen(), commit.getShortMessage()); } } } } } }
关键注意事项
- 目录路径匹配:目标目录
targetDir必须以斜杠结尾,避免误匹配类似x_other/file.txt这类名称相似的路径 - 删除文件处理:当文件被删除时,
DiffEntry的newPath会是/dev/null,此时需要通过oldPath判断是否属于目标目录 - 资源管理:所有实现
AutoCloseable的JGit类(如RevWalk、TreeWalk)都用try-with-resources包裹,避免资源泄漏 - 遍历顺序:默认从最新提交往旧提交遍历,添加
revWalk.sort(RevSort.REVERSE)可改为从旧到新顺序
内容的提问来源于stack exchange,提问作者JF Meier
相关产品推荐
相关产品推荐

