{"record":{"id":"0955b12843373bf1","repo":"elastic/elasticsearch","slug":"found-the-following-merge-commits-which-prevent-de","errorCode":null,"errorMessage":"Found the following merge commits which prevent determining bwc commits: ${mergeCommits}","messagePattern":"Found the following merge commits which prevent determining bwc commits: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/InternalBwcGitPlugin.java","lineNumber":229,"sourceCode":"     * should not matter in practice.\n     */\n    private String maybeAlignedRefSpec(Logger logger, String defaultRefSpec) {\n        if (providerFactory.systemProperty(\"bwc.checkout.align\").isPresent() == false) {\n            return defaultRefSpec;\n        }\n\n        String timeOfCurrent = execInCheckoutDir(execSpec -> {\n            execSpec.commandLine(asList(\"git\", \"show\", \"--no-patch\", \"--no-notes\", \"--pretty='%cD'\"));\n            execSpec.workingDir(buildLayout.getRootDirectory());\n        });\n\n        logger.lifecycle(\"Commit date of current: {}\", timeOfCurrent);\n\n        String mergeCommits = execInCheckoutDir(\n            spec -> spec.commandLine(asList(\"git\", \"rev-list\", defaultRefSpec, \"--after\", timeOfCurrent, \"--merges\"))\n        );\n        if (mergeCommits.isEmpty() == false) {\n            throw new IllegalStateException(\"Found the following merge commits which prevent determining bwc commits: \" + mergeCommits);\n        }\n        return execInCheckoutDir(\n            spec -> spec.commandLine(asList(\"git\", \"rev-list\", defaultRefSpec, \"-n\", \"1\", \"--before\", timeOfCurrent, \"--date-order\"))\n        );\n    }\n\n    private void writeFile(File file, String content) {\n        try {\n            file.getParentFile().mkdirs();\n            Files.writeString(file.toPath(), content, CREATE, TRUNCATE_EXISTING);\n        } catch (IOException e) {\n            throw new UncheckedIOException(e);\n        }\n    }\n\n    private String execInCheckoutDir(Action<ExecSpec> execSpecConfig) {\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        ExecResult exec = execOperations.exec(execSpec -> {","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/InternalBwcGitPlugin.java#L211-L247","documentation":"Thrown as IllegalStateException by maybeAlignedRefSpec() when bwc.checkout.align is set and git rev-list finds merge commits in the refspec between the current commit's date and now. The deterministic BWC-version alignment uses commit timestamps to pick a stable ref; merge commits can introduce backdated commits, breaking determinism, so the code refuses to proceed rather than produce a non-reproducible checkout.","triggerScenarios":"Only fires when -Dbwc.checkout.align is present (line 214). The code runs git rev-list <refspec> --after <currentCommitDate> --merges; any non-empty output throws. Triggered when the branch being aligned contains merge commits dated after the current commit's committer date.","commonSituations":"A feature branch with merge commits from main is being used for aligned BWC builds; rebases that preserved merge commits; testing locally on a branch with merges; CI on a release branch that received merge-back commits.","solutions":["Rebase the branch instead of merging to eliminate merge commits in the window, then re-run.","Unset -Dbwc.checkout.align to skip deterministic alignment and use the default refspec (loses determinism guarantee).","Inspect the listed merge commit SHAs with git log --merges to decide whether to revert or rebase them out.","If the merge commits are intentional and old, advance the current commit date past them so they fall outside the --after window."],"exampleFix":"# before: branch has merge commits, alignment fails\n./gradlew bwcTest -Dbwc.checkout.align=true\n\n# after: rebase to linearize, removing merges\ngit rebase main\n./gradlew bwcTest -Dbwc.checkout.align=true\n\n# or skip alignment\n./gradlew bwcTest","handlingStrategy":"validation","validationCode":"// before enabling align, check for merge commits\nProcess p = new ProcessBuilder(\"git\", \"rev-list\", \"HEAD\", \"--merges\", \"--since=1.month\").start();\nif (p.getInputStream().readAllBytes().length > 0) {\n    System.err.println(\"Merge commits present; skip -Dbwc.checkout.align\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer rebasing over merging on branches used for aligned BWC builds.","Only enable bwc.checkout.align on branches known to be linear (release branches).","Inspect git log --merges before running aligned BWC tests.","Unset bwc.checkout.align when determinism is not required."],"tags":["bwc","git","determinism","gradle"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}