Repository navigation
Backport every commit of a rebase-merged pull request - #80
Draft
aiolibsbot wants to merge 1 commit into
Draft
aiolibsbot wants to merge 1 commit into
aiolibsbot wants to merge 1 commit into
Conversation
GitHub reports a `merge_commit_sha` for every merged pull request, but what that commit holds depends on the merge strategy. A squash-"merge" puts the whole pull request in it. A rebase-"merge" or a fast-forward push replays the pull request's commits onto the base branch and points `merge_commit_sha` at the *last* one. Patchback cherry-picked that single commit either way, so a three-commit rebase-merged pull request was backported as its final commit only — and the check run was still marked green. A partial backport reported as a success is worse than a failed one. Ask Git which of the pull request's commits already landed instead of guessing the strategy: `git cherry <merge commit> <pull request head>` marks each one, since a rebase preserves patch identity. All of them upstream means a replayed series, so pick the `sha~N..sha` range; none means a single squashed commit, so keep picking it alone. A fast-forward is spotted by the head resolving to the merge commit itself, where the commit count from the webhook payload says how far back the series goes. Anything in between those two answers is a shape this cannot name, as is a series whose `~N` range spans a different number of commits than the pull request has — a branchy history rather than the flat one a rebase produces. Both refuse rather than backport a slice of the pull request. The pull request head comes from the `refs/pull/*/head` ref, which also covers pull requests from forks. If fetching it fails, the historical single-commit pick is kept: that is correct for squash-"merges", the default strategy and the common case. Resolves sanitizers#35
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Cherry-pick all the commits a pull request contributed, not just the one GitHub reports as
merge_commit_sha.Why
merge_commit_shameans different things per merge strategy. A squash-"merge" holds the whole PR in it; a rebase-"merge" (and a fast-forward push) replays the PR's commits onto the base branch and pointsmerge_commit_shaat the last one.Patchback picked that single commit either way. A 3-commit rebase-merged PR was backported as its final commit only — and the check run went green. Silent partial backport reported as success.
tests/test_pick_target.py::test_rebase_merge_tip_alone_would_lose_commitspins that premise: the old pick yields 1 of 3 files.Resolves #35.
How
Count, don't classify.
git cherry <merge commit> <PR head>marks each PR commit-/+by patch identity, which a rebase preserves:sha~N..sharangeFast-forward pushes leave no rewritten copies for
git cherryto match, so they're spotted by the PR head resolving tomerge_commit_sha; the payload'scommitscount says how far back the series goes. A~Nrange spanning a different number of commits than the PR has (merge commits in the branch) is refused too.Decisions worth flagging:
refs/pull/*/head— works for forks. If that fetch fails, the historical single-commit pick is kept rather than failing closed: it's correct for squash-"merges", the default strategy. Loudlogger.erroreither way.git cherry-pick <merge commit>step is the exact operation that would drop the rest of the series. On the conflict path the guide is still shown, so the error now carries an explicit note naming the range to pick instead.patchback/pick_target.py— pure, stdlib-only, no I/O.Testing
19 tests,
pytest+gitonly. Beyond the pure unit tests, each merge strategy is built in a real repo (squash / rebase / fast-forward / merge-commits-in-branch) and the resolved target is actually cherry-picked, asserting the backported tree contains every file the PR added.Not done: exact handling of a fast-forwarded branch that contains merge commits — refused instead. Revisit if anyone reports it.
pytest.iniand.github/workflows/tests.ymlare byte-identical to the copies on #72/#73/#77/#79, so add/add merges cleanly whatever the order. Overlaps #79 in the cherry-pick call site.Quality Report
Changes: 5 files changed, 429 insertions(+), 5 deletions(-)
Code scan: clean
Tests: failed (command not found)
Branch hygiene: clean
Generated by Kōan