fix(ci): resolve merge_commit_sha^1 as diff base for merged PRs - #2893
fix(ci): resolve merge_commit_sha^1 as diff base for merged PRs#2893Erik Osterman (Cloud Posse) (osterman) wants to merge 1 commit into
Conversation
When a GitHub Actions checkout for a merged PR isn't pinned to pull_request.head.sha, HEAD can end up on or past the target branch's post-merge tip. resolvePRBase's merge-base tier could then resolve a degenerate, self-referential base (confirmed in production: the resolved --base exactly equaled merge_commit_sha), causing every commit that landed on the target branch between the PR branch cut and the merge to be misreported as "affected" -- up to 510 false positives in one incident. Add a preferred first resolution step for closed/merged PRs that resolves merge_commit_sha^1 directly from the merge commit GitHub created, which is correct regardless of checkout state. Any failure falls through unchanged to the existing 4-tier chain. Also harden the existing merge-base tier to treat a result equal to the checked-out HEAD as a failed resolution for closed PRs, instead of accepting it as a false success.
|
Tip Atmos Pro
No affected stacks workflow was detected for this pull request. |
📝 WalkthroughWalkthroughGitHub merged pull requests now resolve their base from the merge commit’s first parent, with fetch-and-fallback behavior. Closed-PR merge-base results equal to ChangesGitHub merged PR base resolution
Estimated code review effort: 4 (Complex) | ~45 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/ci/providers/github/base_test.go`:
- Around line 697-727: Replace the external-command implementations of runGit
and runGitOutput with Go-native repository fixture and assertion helpers, using
the existing repository utilities or go-git APIs available in the test package.
Preserve their current setup behavior, including deterministic author and
committer identity, and update callers as needed so merge-state tests no longer
depend on an installed Git binary.
In `@pkg/ci/providers/github/base.go`:
- Around line 240-252: Update resolveMergedPRTier so commitParentSHA(0) is not
used unconditionally for merge_commit_sha; distinguish actual merge commits from
squash and rebase commits, and use an appropriate merge-base or fallback
resolution for non-merge commits. Preserve complete PR change coverage for
squash and multi-commit rebase merges, and add tests covering both cases.
- Around line 603-610: Update fetchCommitSHA to ensure the fetched history
includes the merge commit’s first parent before returning, either by fetching
the parent explicitly or deepening the repository until commitParentSHA
succeeds. Preserve the existing error reporting, and add a regression case
covering a merge commit available only on origin.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 17eaf4d4-d42b-482e-a218-93c5d42a0221
📒 Files selected for processing (3)
docs/fixes/2026-08-06-github-merged-pr-diff-base.mdpkg/ci/providers/github/base.gopkg/ci/providers/github/base_test.go
| // runGit runs a git command in dir, failing the test on error. | ||
| func runGit(t *testing.T, dir string, args ...string) { | ||
| t.Helper() | ||
| cmd := exec.Command("git", args...) | ||
| cmd.Dir = dir | ||
| cmd.Env = append( | ||
| os.Environ(), | ||
| "GIT_AUTHOR_NAME=Test", | ||
| "GIT_AUTHOR_EMAIL=test@test.com", | ||
| "GIT_COMMITTER_NAME=Test", | ||
| "GIT_COMMITTER_EMAIL=test@test.com", | ||
| ) | ||
| output, err := cmd.CombinedOutput() | ||
| require.NoError(t, err, "git %v failed: %s", args, string(output)) | ||
| } | ||
|
|
||
| // runGitOutput runs a git command in dir and returns trimmed stdout. | ||
| func runGitOutput(t *testing.T, dir string, args ...string) string { | ||
| t.Helper() | ||
| cmd := exec.Command("git", args...) | ||
| cmd.Dir = dir | ||
| cmd.Env = append( | ||
| os.Environ(), | ||
| "GIT_AUTHOR_NAME=Test", | ||
| "GIT_AUTHOR_EMAIL=test@test.com", | ||
| "GIT_COMMITTER_NAME=Test", | ||
| "GIT_COMMITTER_EMAIL=test@test.com", | ||
| ) | ||
| out, err := cmd.Output() | ||
| require.NoError(t, err, "git %v failed", args) | ||
| return strings.TrimSpace(string(out)) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file outline =="
ast-grep outline pkg/ci/providers/github/base_test.go --view compact || true
echo "== relevant lines =="
sed -n '660,740p' pkg/ci/providers/github/base_test.go | cat -n
echo "== git command usages in test =="
rg -n "runGit|exec\.Command\(\"git\"|Command\(\"git\"|exec\.Command\\(" pkg/ci/providers/github/base_test.go || true
echo "== Go imports mentioning git/gitlab/go-git =="
sed -n '1,80p' pkg/ci/providers/github/base_test.go | cat -n
echo "== existing repository helper candidates =="
rg -n "go-git|initRepo|InitRepo|CreateGitRepo|git init|RunCommand|Command\\(" pkg internal || trueRepository: cloudposse/atmos
Length of output: 50372
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== repo git files/status =="
git status --short || true
echo "== go.mod go-git references =="
rg -n "github\\.com/src-d/go-git|github\\.com/go-git/go-git|gopkg.in/src-d/go-git" go.mod go.sum || true
echo "== module files =="
[ -f go.mod ] && sed -n '1,120p' go.modRepository: cloudposse/atmos
Length of output: 6069
Replace Git CLI test helpers with Go-native fixture helpers.
runGit and runGitOutput spawn external git commands for repository setup and assertions. Build the merge-state fixture with an existing Go-native helper or go-git, since tests should not depend on installed platform binaries.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pkg/ci/providers/github/base_test.go` around lines 697 - 727, Replace the
external-command implementations of runGit and runGitOutput with Go-native
repository fixture and assertion helpers, using the existing repository
utilities or go-git APIs available in the test package. Preserve their current
setup behavior, including deterministic author and committer identity, and
update callers as needed so merge-state tests no longer depend on an installed
Git binary.
Source: Coding guidelines
| func resolveMergedPRTier(payload map[string]any, action, headSHA, targetBranch, eventName string) *provider.BaseResolution { | ||
| if action != "closed" || !isPRMerged(payload) { | ||
| return nil | ||
| } | ||
|
|
||
| mergeCommitSHA := extractMergeCommitSHA(payload) | ||
| if mergeCommitSHA == "" { | ||
| return nil | ||
| } | ||
|
|
||
| sha, err := resolveMergeCommitParent(mergeCommitSHA) | ||
| if err != nil { | ||
| log.Debug("merge_commit_sha^1 failed, trying fallbacks", "merge_commit_sha", mergeCommitSHA, "error", err) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
fd -a 'base\.go$' . | sed 's#^\./##' | head -50
echo
echo "== target lines =="
if [ -f pkg/ci/providers/github/base.go ]; then
sed -n '200,320p' pkg/ci/providers/github/base.go | cat -n
fi
echo
echo "== relevant helpers =="
rg -n "resolveMergeCommitParent|commitParentSHA|fetchCommitSHA|resolveMergedPRTier|merge_commit_sha|first.*parent|Parent\\("pkg/ci/providers/github/base.go pkg/ci/providers/github pkg/ci -SRepository: cloudposse/atmos
Length of output: 12133
🌐 Web query:
GitHub REST API pulls merge_commit_sha rebase merge no merge commit
💡 Result:
The GitHub REST API provides the merge_commit_sha attribute in the pull request resource, but its meaning and behavior depend on the state of the pull request and the method used to merge it [1][2]. Before a pull request is merged, merge_commit_sha represents the SHA of a temporary test merge commit created by GitHub to verify if the branch can be automatically merged without conflicts [1][3][2]. This test commit is not added to the base or head branches [4][2]. After a pull request is merged, the value of merge_commit_sha changes based on the merge method used [1][2]: 1. Merge Commit: The attribute holds the SHA of the actual merge commit created on the base branch [1][2]. 2. Squash and Merge: The attribute holds the SHA of the single squashed commit added to the base branch [1][2]. 3. Rebase and Merge: Since rebase and merge adds commits from the head branch onto the base branch individually—creating a linear history without a traditional merge commit—the merge_commit_sha attribute represents the SHA of the last commit that the base branch was updated to (i.e., the final commit from the head branch that was rebased onto the base) [1][2][5]. Note that while the field is sometimes referred to as merge_commit_sha, for rebased pull requests, it identifies the commit resulting from the rebase process on the base branch [1][2]. If you are experiencing unexpected null values for this field after a merge, it may indicate a temporary system issue or that the background metadata generation process has not yet completed [6].
Citations:
- 1: https://docs.github.com/en/rest/pulls/pulls
- 2: https://docs.github.com/en/rest/pulls/pulls?apiVersion=2026-03-10
- 3: https://www.kenmuse.com/blog/the-many-shas-of-a-github-pull-request/
- 4: https://github.com/github/developer.github.com/blob/master/content/v3/pulls.md
- 5: https://docs.github.com/en/pull-requests/reference/pull-request-merges
- 6: https://stackoverflow.com/questions/79325022/what-would-cause-a-github-prs-merge-commit-sha-to-be-null
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== helper implementations =="
sed -n '540,625p' pkg/ci/providers/github/base.go | cat -n
echo
echo "== tier 0 docs/comments around merge commits =="
sed -n '80,135p' pkg/ci/providers/github/base.go | cat -n
echo
echo "== tests around resolved merge commit and fallback behavior =="
sed -n '720,910p' pkg/ci/providers/github/base_test.go | cat -n
echo
echo "== git shallow/fetch-related refs in github provider =="
rg -n "depth|fetch \+|fetch --|git fetch|fetchCommitSHA|commitParentSHA|shallow|single-commit" pkg/ci/providers/github/base.go pkg/ci/providers/github/base_test.go pkg/ci providers pkg -SRepository: cloudposse/atmos
Length of output: 50373
🌐 Web query:
site:docs.github.com/rest/pulls/pulls merge_commit_sha rebase squash merged
💡 Result:
In GitHub’s Pull Request REST API, merge_commit_sha means:
- Merge commit: SHA of the merge commit on the base branch.
- Squash merge: SHA of the newly created squashed commit on the base branch.
- Rebase merge: SHA of the last commit added to the base branch.
- Unmerged/open PR: May be
null; GitHub may still populate it with a temporary test merge commit. (docs.github.com)
Citations:
Do not resolve every merge_commit_sha with commitParentSHA(0).
For squash and rebase merges, merge_commit_sha is a regular commit added to the target branch, not a merge commit with the target tip as parent(0). A multi-PR-commit rebase leaves parent(0) as an earlier rebased commit, so tier 0 can omit later PR changes. Gate this path on actual merge commits, add coverage for squash/rebase cases, or use merge-base as base resolution for all merge types.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pkg/ci/providers/github/base.go` around lines 240 - 252, Update
resolveMergedPRTier so commitParentSHA(0) is not used unconditionally for
merge_commit_sha; distinguish actual merge commits from squash and rebase
commits, and use an appropriate merge-base or fallback resolution for non-merge
commits. Preserve complete PR change coverage for squash and multi-commit rebase
merges, and add tests covering both cases.
Source: MCP tools
| func fetchCommitSHA(sha string) error { | ||
| defer perf.Track(nil, "github.fetchCommitSHA")() | ||
|
|
||
| cmd := exec.Command("git", "fetch", "origin", sha, "--no-tags", "--depth=1") | ||
| cmd.Dir = "." | ||
| output, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| return fmt.Errorf("fetching commit %s from origin: %w\n%s", sha, err, string(output)) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
git ls-files | rg '(^|/)pkg/ci/providers/github/base\.go$' || true
echo "== outline around file =="
wc -l pkg/ci/providers/github/base.go
ast-grep outline pkg/ci/providers/github/base.go --view compact | sed -n '1,260p'
echo "== relevant lines 560-640 =="
sed -n '560,640p' pkg/ci/providers/github/base.go | nl -ba -v560
echo "== usages of fetchCommitSHA and Parent =="
rg -n "fetchCommitSHA|\\.Parent\\(|Parents\\(" pkg/ci/providers/github/base.go pkg -g '*.go' | sed -n '1,120p'Repository: cloudposse/atmos
Length of output: 417
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== relevant lines 560-640 =="
sed -n '560,640p' pkg/ci/providers/github/base.go | nl -ba -v560
echo "== usages of fetchCommitSHA and Parent/Parents =="
rg -n "fetchCommitSHA|\\.Parent\\(|Parents\\(" pkg/ci/providers/github/base.go pkg -g '*.go' | sed -n '1,160p'
echo "== surrounding function call paths =="
rg -n "fetchCommitSHA|GetCommit|CommitSHA|GetBuild\\(" pkg/ci/providers/github/base.go -C 3 | sed -n '1,220p'Repository: cloudposse/atmos
Length of output: 223
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== relevant lines 560-640 =="
sed -n '560,640p' pkg/ci/providers/github/base.go | awk '{printf "%6d: %s\n", NR+559, $0}'
echo "== usages of fetchCommitSHA and Parent/Parents =="
rg -n "fetchCommitSHA|\\.Parent\\(|Parents\\(" pkg/ci/providers/github/base.go pkg -g '*.go' || true
echo "== surrounding function call paths =="
rg -n "fetchCommitSHA|GetCommit|CommitSHA|GetBuild\\(" pkg/ci/providers/github/base.go -C 3 | sed -n '1,220p' || trueRepository: cloudposse/atmos
Length of output: 6258
🌐 Web query:
git fetch --depth=1 documentation fetches only <commit> and objects needed by it
💡 Result:
When you use git fetch --depth=1, it limits the amount of history downloaded from the remote repository. Specifically, it fetches only the tip of the remote branch(es) (the most recent commit) and the objects required to support that commit, excluding any older historical commits [1][2]. However, the behavior depends on the target provided: 1. Standard usage: When running git fetch --depth=1 origin, Git fetches the latest commit (and its necessary objects) for the remote branches [1][2]. 2. Fetching a specific commit: If you provide a specific hash (e.g., git fetch --depth=1 origin ), Git will attempt to fetch that specific commit [3][4]. This requires the remote repository to have the uploadpack.allowReachableSHA1InWant configuration set to true [3][4]. If enabled, this command fetches the specified commit and the objects reachable from it, effectively creating a shallow repository containing only that commit and its dependencies [3]. Key technical points: - Reachability: Git downloads all objects (trees and blobs) reachable from the specified tip or commit [3]. - Server-side requirements: Fetching an arbitrary commit hash that is not a branch tip typically requires explicit server-side permission (allowReachableSHA1InWant) [3][4]. - Limitations: The --depth option is designed to create or update shallow repositories [1][5]. Tags associated with the deepened commits are not fetched by default [1]. In summary, while git fetch --depth=1 is commonly used to fetch the latest commit of a branch, it can also be used to fetch a specific commit if the server permits it, limiting the download to that commit's history and its necessary tree/blob objects [3].
Citations:
- 1: https://git-scm.com/docs/git-fetch.html
- 2: https://graphite.com/guides/git-fetch-depth
- 3: https://stackoverflow.com/questions/14872486/retrieve-specific-commit-from-a-remote-git-repository
- 4: https://stackoverflow.com/questions/31278902/how-to-shallow-clone-a-specific-commit-with-depth-1
- 5: https://git-scm.com/docs/git-fetch
🌐 Web query:
git fetch shallow depth-1 object hierarchy blob tree ignore commit parent parent sha git
💡 Result:
When you run git fetch with --depth=1, Git retrieves only the most recent commit at the tip of the specified branch [1][2]. Regarding the object hierarchy and data downloaded: 1. Commits: Only the commit at the tip (and its associated metadata) is fetched [2]. The connection to parent commits is severed; these are treated as shallow commits, and their parent information is ignored or effectively removed in your local repository [3][2][4]. 2. Blobs and Trees: Git downloads all the tree and blob objects necessary to construct the file system state for that specific, most recent commit [2]. Even though you are restricting the history (the commit chain), you still receive the full content (files and directories) corresponding to that commit [2]. 3. Ignoring Parent/SHA: The shallow boundary is maintained by a file at.git/shallow [3][4]. This file lists the commit SHA-1s where the history has been truncated, instructing Git to treat these as root commits—meaning they are perceived as having no parents, regardless of their actual history on the remote repository [3][4]. In summary, a depth-1 fetch prioritizes the current state of the files (trees and blobs) while truncating the historical commit graph to just the tip [2].
Citations:
- 1: https://git-scm.com/docs/git-fetch.html
- 2: https://github.blog/open-source/git/get-up-to-speed-with-partial-clone-and-shallow-clone/
- 3: https://git-scm.com/docs/shallow
- 4: https://www.kernel.org/pub/software/scm/git/docs/technical/shallow.html
🌐 Web query:
git fetch --depth=1 fetch arbitrary sha commit parent object file .git/shallow
💡 Result:
Attempting to use git fetch --depth=1 to retrieve an arbitrary commit SHA directly is generally unreliable because most Git servers disable the ability to request unadvertised objects by default [1][2][3]. For a git fetch command to successfully retrieve a specific SHA-1, the Git server must have the configuration uploadpack.allowReachableSHA1InWant=true enabled [1][3]. If this setting is not configured, the server will reject the request with an error such as fatal: Server does not allow request for unadvertised object [2]. When this feature is disabled (which is the default for most hosting providers and servers for security and performance reasons), git fetch will only permit fetching objects that are advertised by the server, such as branch tips or tags [4][5]. To work around this limitation in shallow repositories or when trying to fetch a specific commit, consider the following approaches: 1. Identify the Ref: If the commit belongs to a branch or tag, fetch that ref instead of the raw SHA [4]. 2. Increase Depth: If you are in a shallow repository, you may need to gradually increase the depth of your fetch (e.g., --depth=50, --depth=100) until the commit becomes reachable within the fetched history [1][2]. 3. Shallow Clone with Revision (Git 2.49+): If your environment uses a modern version of Git, the --revision option can be used with git clone to fetch history leading up to a specific revision [1]. The.git/shallow file is an internal Git mechanism that tracks which commits are considered root commits in a shallow repository [6]. It is managed automatically by Git commands like git fetch --depth=N and should not be edited manually [6].
Citations:
- 1: https://stackoverflow.com/questions/31278902/how-to-shallow-clone-a-specific-commit-with-depth-1
- 2: https://stackoverflow.com/questions/46208207/fetch-git-repo-at-specific-commit-without-cloning
- 3: git_repository should --depth=1 fetch of sha1 bazelbuild/bazel#8969
- 4: https://stackoverflow.com/questions/70703600/fastest-way-to-fetch-specific-commit-from-outdated-full-clone
- 5: https://public-inbox.org/git/20160519015323.GA24225@sigill.intra.peff.net/T/
- 6: https://git-scm.com/docs/shallow
🌐 Web query:
Git's shallow fetch commit objects blobs trees not parent objects fetch-depth
💡 Result:
When you perform a shallow fetch or clone in Git using the --depth option, Git limits the history of the repository by restricting how many commit objects are transferred from the remote server [1][2]. In a shallow repository: 1. Commit Objects: Only the specified number of commits (measured from the tip of the branches) are transferred [2][3]. The commit that sits at the boundary of this depth is marked as a shallow commit [1][4][5]. 2. Shallow Boundary and Parent Objects: A shallow commit does not have its parent commits available in the local repository [1][4][5]. To handle this, Git maintains a file named.git/shallow, which lists the object names of these commits [1][4]. Git treats these commits as if they were root commits (i.e., they have no parents), effectively "grafting" the history to make traversal stop at these points [1][4][6]. 3. Blobs and Trees: Git downloads only the tree and blob objects necessary to reconstruct the states of the commits that are fetched [7][5]. If a commit is not fetched, its corresponding tree and blob objects are generally not downloaded either, as they are not needed to represent the partial history [5]. 4. Depth Calculation: The --depth parameter refers to the number of commits in a chain [3]. If a commit in that chain is a merge commit, it contributes to the depth count just like any other commit; however, because merge commits have multiple parents, a shallow fetch can technically result in more than --depth commits being present if those parents are reachable within the truncated history [3]. In summary, shallow operations reduce repository size by omitting historical objects (commits, trees, and blobs) that fall outside the specified depth, using the.git/shallow file to track and manage these boundaries [1][2][4].
Citations:
- 1: https://git-scm.com/docs/shallow
- 2: https://git-scm.dev/docs/git-fetch
- 3: https://stackoverflow.com/questions/53683896/what-does-depth-for-git-clone-mean
- 4: https://github.com/git/git/blob/94f057755b7941b321fd11fec1b2e3ca5313a4e0/Documentation/technical/shallow.adoc
- 5: https://public-inbox.org/git/7v1uz55r24.fsf@alter.siamese.dyndns.org/t/
- 6: https://www.kernel.org/pub/software/scm/git/docs/technical/shallow.html
- 7: https://git.github.io/htmldocs/git-fetch.html
Fetch the merge commit parent before retrying.
git fetch --depth=1 stops at the requested commit SHA, so commit.Parent(0) can still fail for a locally absent merge commit. Fetch the first parent as well, or deepen until commitParentSHA() succeeds before returning. Add a regression case where the merge commit exists only on origin.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pkg/ci/providers/github/base.go` around lines 603 - 610, Update
fetchCommitSHA to ensure the fetched history includes the merge commit’s first
parent before returning, either by fetching the parent explicitly or deepening
the repository until commitParentSHA succeeds. Preserve the existing error
reporting, and add a regression case covering a merge commit available only on
origin.
Source: MCP tools
|
Closing — the justification for this was a customer incident (510 false-positive affected components) that I attributed to this exact resolvePRBase failure mode. I've since confirmed that incident's actual root cause was unrelated: the customer's own workflow passed an explicit --base flag that never touches this code path at all. The self-referential merge-base result this PR guards against is still a real theoretical gap, but I no longer have a confirmed case of it happening. Reopening later with real evidence if one turns up. |
what
resolvePRBase(pkg/ci/providers/github/base.go) now resolvesmerge_commit_sha^1as a preferred first step for closed/mergedpull_requestevents, before falling into the existingmerge-base(HEAD, origin/<target>)→HEAD~1→event.pull_request.base.sha→ ref fallback chain.merge-basetier now treats a result equal to the checked-outHEADas a failed resolution for closed PRs (instead of accepting it as a valid base), as a secondary guard against the same failure class whenmerge_commit_shais unavailable.docs/fixes/2026-08-06-github-merged-pr-diff-base.mdrecording the fix per repo convention.why
atmos describe affected --uploadin GitHub Actions withci.enabled: trueauto-resolves the diff base for merged PRs. If the workflow's checkout isn't pinned topull_request.head.sha,HEADcan end up on or past the target branch's post-merge tip, causing the existing merge-base tier to resolve a degenerate, self-referential base.--baseexactly equaled the PR'smerge_commit_sha— the fingerprint of this exact degeneracy.merge_commit_sha^1(the merge commit's first parent) is derived from the merge commit GitHub itself created when the PR was merged, so it's correct regardless of what the workflow happened to check out.references
Summary by CodeRabbit
Bug Fixes
Documentation