diff --git a/src/main/java/com/example/workutils/biz/gitreview/GitReviewService.java b/src/main/java/com/example/workutils/biz/gitreview/GitReviewService.java index 4cd2b19..4dc87ad 100644 --- a/src/main/java/com/example/workutils/biz/gitreview/GitReviewService.java +++ b/src/main/java/com/example/workutils/biz/gitreview/GitReviewService.java @@ -154,12 +154,51 @@ public class GitReviewService { } } + /** + * 工作区检查时忽略的路径模式。 + * 支持精确匹配文件名(如 ".gitignore")和目录前缀匹配(如 ".codefree/")。 + */ + private static final List STATUS_IGNORE_PATTERNS = Collections.unmodifiableList( + Arrays.asList(".gitignore", ".codefree/")); + private boolean hasLocalChanges(Path projectPath) { CmdResult status = run(projectPath, "git", "status", "--porcelain"); if (!status.ok) { throw new IllegalStateException("检查工作区状态失败: " + status.error); } - return !status.output.trim().isEmpty(); + // status.output 已在 run() 中 trim 过,不要再 trim,否则会删除首行前导空格导致解析错位 + String output = status.output; + if (output == null || output.isEmpty()) { + return false; + } + // 过滤掉忽略的路径,只检查实际关心的改动 + for (String line : output.split("\\R")) { + if (line.isEmpty()) { + continue; + } + // git status --porcelain 每行:前2字符是状态码(XY),第3字符是空格,之后是路径 + // 用正则 "^\S\S\s" 跳过状态码前缀,直接取路径 + String filePath = line.replaceFirst("^.{2}\\s+", ""); + // 处理重命名 "orig -> new",取 newpath + int arrowIdx = filePath.indexOf(" -> "); + if (arrowIdx > 0) { + filePath = filePath.substring(arrowIdx + 4); + } + log.debug("git status 行: [{}], 提取路径: [{}], 是否忽略: {}", line, filePath, isIgnoredPath(filePath)); + if (!isIgnoredPath(filePath)) { + return true; // 存在非忽略的改动,返回 true + } + } + return false; // 所有改动都是被忽略的 + } + + private boolean isIgnoredPath(String path) { + for (String pattern : STATUS_IGNORE_PATTERNS) { + if (path.equals(pattern) || path.startsWith(pattern)) { + return true; + } + } + return false; } private void fetchBranch(Path projectPath, String branch, LogSink logs) {