JGIT重复执行合并冲突代码触发空指针异常原因排查
首先,咱们来拆解你重复执行这段JGit合并代码时出现空指针的核心原因——仓库状态污染,这确实和Git的核心机制有关,也涉及JGit的具体行为。
为什么会出现空指针?
你的代码里,空指针发生在tmpMergeRes.getConflicts()这一行,大概率是因为第二次调用tmpMerge.call()时抛出了异常,导致tmpMergeRes没有被正常赋值。而触发异常的根源是:
Git本身不允许在仓库处于「未完成合并状态」时执行新的合并操作。你第一次执行dry run(setCommit(false))时,虽然没有提交合并结果,但JGit会修改仓库的索引(甚至工作区)来模拟合并冲突状态——这会让仓库进入「合并中」的特殊状态。当你第二次运行合并代码时,Git检测到仓库还处于未完成的合并状态,直接拒绝执行新的合并,抛出GitAPIException,而你的代码没有捕获这个异常,导致tmpMergeRes保持为null,后续调用getConflicts()就触发了空指针。
另外还有一种可能:如果第二次合并时没有冲突(比如分支状态在第一次测试后发生了变化),tmpMergeRes.getConflicts()可能返回null,但直接赋值给Map类型变量时,如果后续有操作这个Map的代码(比如你的循环),也会触发空指针。不过结合你反复生成冲突的场景,第一种情况的概率更高。
怎么解决?
针对你的测试场景(反复生成合并冲突),可以从以下几个方面修改代码:
1. 每次测试后重置仓库状态
在每次合并dry run完成后,立即撤销合并产生的临时状态,让仓库回到干净的状态。可以用JGit的ResetCommand来硬重置,或者直接终止合并:
// 执行完合并逻辑后,重置仓库到合并前的状态 git.reset() .setMode(ResetType.HARD) .setRef("HEAD") .call(); // 或者如果仓库处于合并冲突状态,可以用abort(JGit 5.0+支持) // git.merge().abort().call();
这样每次测试前,仓库都是干净的,不会因为残留的合并状态导致新的合并失败。
2. 捕获合并异常,避免空指针
给tmpMerge.call()加上异常捕获逻辑,确保即使合并失败,也能优雅处理,而不是让tmpMergeRes为null:
try { tmpMergeRes = tmpMerge.call(); Map<String, int[][]> allConflicts = tmpMergeRes.getConflicts(); // 处理冲突逻辑 if (allConflicts != null) { // 先判空,避免无冲突时返回null导致空指针 for (Map.Entry<String, int[][]> entry : allConflicts.entrySet()) { System.out.println("Key: " + entry.getKey()); for(int[] arr : entry.getValue()) { System.out.println("value: " + Arrays.toString(arr)); } } } } catch (GitAPIException e) { // 处理合并失败的情况,比如打印日志、重置仓库 e.printStackTrace(); // 这里可以加上重置仓库的代码 git.reset().setMode(ResetType.HARD).setRef("HEAD").call(); }
注意要给Map加上泛型声明(Map<String, int[][]>),同时在使用getConflicts()后先判空,避免无冲突时返回null导致后续操作空指针。
3. 确保分支状态每次一致
如果你的测试依赖固定的分支状态来生成冲突,建议每次测试前先从原始分支重置sideMerge分支,或者使用临时分支来测试,避免多次测试后分支状态变化导致冲突消失。比如:
// 每次测试前,重置sideMerge分支到某个固定的commit git.branchCreate() .setName("sideMerge") .setStartPoint("origin/sideMerge-fix") // 用一个固定的测试分支起点 .setForce(true) // 强制覆盖现有分支 .call();
补充说明
Git的合并机制本身要求仓库处于干净状态(没有未提交的修改、没有未完成的合并)才能执行新的合并操作。JGit作为Git的Java实现,严格遵循了这个规则——dry run虽然不提交,但会模拟合并过程修改索引,留下合并状态,这是你遇到问题的核心。只要每次测试后清理状态,就能避免重复执行时的异常。
内容的提问来源于stack exchange,提问作者Szilágyi István

