Skip to content

Commit 5d4321e

Browse files
kriszypclaude
andcommitted
fix(cherry-pick): handle rebase merges and open conflict PRs for merged patches
- For squash/rebase merges (PARENT_COUNT==1), pick original PR commits (MERGE_BASE..HEAD_SHA) instead of just MERGE_SHA. For rebase merges MERGE_SHA is only the last rebased commit, silently skipping earlier ones. - When a merged PR's cherry-pick conflicts, open a PR against the release branch so the conflict can be resolved and merged without any future trigger from the already-closed original PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4720676 commit 5d4321e

1 file changed

Lines changed: 32 additions & 4 deletions

File tree

.github/workflows/cherry-pick-patch.yml

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,22 @@ jobs:
129129
130130
# ── Determine commits to pick ───────────────────────────────────
131131
if [ "$IS_MERGED" = "true" ]; then
132-
# Merged: pick the merge commit (squash/rebase/merge all work)
133132
PARENT_COUNT=$(git cat-file -p "$MERGE_SHA" | grep -c "^parent ")
134133
if [ "$PARENT_COUNT" -gt 1 ]; then
134+
# True merge commit: cherry-pick it directly with -m 1
135135
PICK_FLAGS="-m 1"
136136
PICK_SHAS="$MERGE_SHA"
137137
else
138+
# Squash or rebase merge: pick the original PR commits so we get
139+
# the full set. For squash this is equivalent (same net diff). For
140+
# rebase, MERGE_SHA is only the last rebased commit — the earlier
141+
# ones would be silently skipped if we picked MERGE_SHA alone.
142+
MERGE_BASE=$(git merge-base "$BASE_SHA" "$HEAD_SHA")
138143
PICK_FLAGS=""
139-
PICK_SHAS="$MERGE_SHA"
144+
PICK_SHAS=$(git rev-list --reverse "${MERGE_BASE}..${HEAD_SHA}" | tr '\n' ' ')
145+
if [ -z "$(echo "$PICK_SHAS" | tr -d ' ')" ]; then
146+
PICK_SHAS="$MERGE_SHA"
147+
fi
140148
fi
141149
else
142150
# Open PR: pick the commit range merge_base..HEAD
@@ -190,12 +198,32 @@ jobs:
190198
if: github.event.action != 'unlabeled' && steps.pick.outputs.conflicts != ''
191199
env:
192200
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
201+
IS_MERGED: ${{ steps.pick.outputs.is_merged }}
202+
PR_TITLE: ${{ steps.pick.outputs.pr_title }}
193203
run: |
194204
set -euo pipefail
195205
BRANCH="${{ steps.pick.outputs.branch }}"
196206
CONFLICTS="${{ steps.pick.outputs.conflicts }}"
197-
BODY=$(printf '%s\n## Patch cherry-pick: conflict\n\nCherry-pick onto `%s` produced conflicts on commit(s): `%s`\n\nThe conflict markers are committed on branch [`%s`](../tree/%s).\nIntegration tests are **not** running until conflicts are resolved.\n\n@claude please review branch `%s` and suggest a patch that resolves the conflict markers (`<<<<<<<` / `=======` / `>>>>>>>`) introduced by cherry-picking PR #%s onto `%s`. Post the suggested patch as a comment on this PR — do not push.\n' \
198-
"$STICKY_MARKER" "$RELEASE_BRANCH" "$CONFLICTS" "$BRANCH" "$BRANCH" "$BRANCH" "$PR_NUMBER" "$RELEASE_BRANCH")
207+
208+
if [ "$IS_MERGED" = "true" ]; then
209+
# PR already merged — open a release-branch PR so the conflict can
210+
# be resolved and merged without any future trigger from the original PR.
211+
PATCH_PR_URL=$(gh pr list --repo "$GITHUB_REPOSITORY" \
212+
--base "$RELEASE_BRANCH" --head "$BRANCH" --json url --jq '.[0].url' 2>/dev/null || true)
213+
if [ -z "$PATCH_PR_URL" ] || [ "$PATCH_PR_URL" = "null" ]; then
214+
PATCH_PR_URL=$(gh pr create --repo "$GITHUB_REPOSITORY" \
215+
--base "$RELEASE_BRANCH" \
216+
--head "$BRANCH" \
217+
--title "cherry-pick: ${PR_TITLE} (conflicts → ${RELEASE_BRANCH})" \
218+
--body "$(printf 'Cherry-pick of PR #%s onto \`%s\` produced conflicts on commit(s): \`%s\`.\n\nResolve the conflict markers on branch \`%s\` and merge this PR.\n\n@claude please review branch \`%s\` and suggest a patch that resolves the conflict markers (`<<<<<<<` / `=======` / `>>>>>>>`) introduced by cherry-picking PR #%s onto \`%s\`. Post the suggested patch as a comment here — do not push.\n' \
219+
"$PR_NUMBER" "$RELEASE_BRANCH" "$CONFLICTS" "$BRANCH" "$BRANCH" "$PR_NUMBER" "$RELEASE_BRANCH")")
220+
fi
221+
BODY=$(printf '%s\n## Patch cherry-pick: conflict\n\nCherry-pick onto `%s` produced conflicts on commit(s): `%s`\n\nThe conflict markers are committed on branch [`%s`](../tree/%s).\nA pull request has been opened to land this patch: %s\n' \
222+
"$STICKY_MARKER" "$RELEASE_BRANCH" "$CONFLICTS" "$BRANCH" "$BRANCH" "$PATCH_PR_URL")
223+
else
224+
BODY=$(printf '%s\n## Patch cherry-pick: conflict\n\nCherry-pick onto `%s` produced conflicts on commit(s): `%s`\n\nThe conflict markers are committed on branch [`%s`](../tree/%s).\nIntegration tests are **not** running until conflicts are resolved.\n\n@claude please review branch `%s` and suggest a patch that resolves the conflict markers (`<<<<<<<` / `=======` / `>>>>>>>`) introduced by cherry-picking PR #%s onto `%s`. Post the suggested patch as a comment on this PR — do not push.\n' \
225+
"$STICKY_MARKER" "$RELEASE_BRANCH" "$CONFLICTS" "$BRANCH" "$BRANCH" "$BRANCH" "$PR_NUMBER" "$RELEASE_BRANCH")
226+
fi
199227
node "$RUNNER_TEMP/upsert-sticky-comment.js" "$PR_NUMBER" "$STICKY_MARKER" "$BODY"
200228
201229
# ── Success path (open PR): trigger tests, wait, report ─────────────

0 commit comments

Comments
 (0)