Push the base-branch merge before asking for conflict resolution#33
Merged
Conversation
Alternative to #32 for the same stuck-PR bug — pick one. After a parent PR is squash-merged, updating a descendant branch runs three merges: the parent branch, the target's pre-squash state, then the squash recorded with `-s ours`. When the pre-squash merge conflicted, the action commented and labeled without pushing anything, so the head was left missing both the base merge and the squash record. The branch never became mergeable, and because GitHub skips `pull_request` workflows on a PR that conflicts with its base, the `synchronize` event that resumes the action never fired again — permanently stuck. This splits the work so the user only resolves the genuine conflict: - When the base-branch merge is clean and only the pre-squash merge conflicts, push the base merge to the branch before commenting and labeling. The head stays a descendant of its base, so the PR stays mergeable and the resume trigger keeps firing. If the base merge itself conflicts there is nothing safe to pre-push, so the existing comment-and-label fallback runs. - After the user resolves and pushes, continue_after_resolution records the squash with `-s ours` and pushes before retargeting. The synchronize payload is the child PR, so the squash commit and new target are reconstructed from the merged parent PR (its merge commit and base). The conflict comment is unchanged: it already lists the genuine conflict. Offline test covers both halves: the squash-merge run pushes the base merge before the unchanged comment, and the follow-up run records the squash so the branch ends up mergeable into the new target. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phlogistique
force-pushed
the
push-base-merge-before-conflict-comment
branch
from
May 29, 2026 14:55
63f61f8 to
562ba64
Compare
Pushing the base merge before commenting leaves the user's local branch behind origin, so following the comment verbatim resolved on a stale head and the final push was rejected as non-fast-forward. The recipe now fast-forwards with `git pull --ff-only origin <branch>` first. The standalone offline test is dropped. The existing e2e conflict scenario already triggers the clean-base-merge / conflicting-pre-squash case, so it now asserts the action pushed the base merge on top of the pre-conflict head and that the comment asks only for the genuine conflict, then resolves by following the comment verbatim (re-sync included) and checks the squash gets recorded so the branch ends up mergeable into the new target. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phlogistique
commented
May 29, 2026
Comment on lines
+115
to
+123
| # When the base merge was clean we already pushed it to this branch, | ||
| # so the local branch is now behind origin. Fast-forward to it before | ||
| # resolving, otherwise the final push is rejected as non-fast-forward. | ||
| # The line is a harmless no-op on the fallback path (nothing pushed). | ||
| if [[ "$BASE_MERGE_CLEAN" == true ]]; then | ||
| echo "git pull --ff-only origin $BRANCH # pick up the base merge this action already pushed" | ||
| else | ||
| echo "git pull --ff-only origin $BRANCH" | ||
| fi |
Collaborator
Author
There was a problem hiding this comment.
Suggested change
| # When the base merge was clean we already pushed it to this branch, | |
| # so the local branch is now behind origin. Fast-forward to it before | |
| # resolving, otherwise the final push is rejected as non-fast-forward. | |
| # The line is a harmless no-op on the fallback path (nothing pushed). | |
| if [[ "$BASE_MERGE_CLEAN" == true ]]; then | |
| echo "git pull --ff-only origin $BRANCH # pick up the base merge this action already pushed" | |
| else | |
| echo "git pull --ff-only origin $BRANCH" | |
| fi | |
| echo "git pull --ff-only origin $BRANCH" |
The sibling conflict scenario still resolved branches with a hardcoded merge against main, so it could pass even if the generated instructions regressed. Reusing the comment-following path makes PR6 and PR7 validate the same workflow users run, while keeping the PR3 flow on the shared helper.
- Note that the base-merge push must precede the label, or the synchronize it emits re-triggers this action against an unresolved branch. - Collapse the duplicated `git pull --ff-only` recipe line to one echo plus a conditional trailing comment. - Fold the new-target and squash-commit lookups into a single `gh pr list` call; `// ""` keeps the absent-PR guard firing. - Reword the continuation conflict message to say it re-posted the comment and will retry, since the path is self-healing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phlogistique
commented
Jun 1, 2026
Phlogistique
commented
Jun 1, 2026
Co-authored-by: Noé Rubinstein <noe.rubinstein@gmail.com>
Phlogistique
added a commit
that referenced
this pull request
Jun 1, 2026
The base branch accepted review suggestions while the stacked branch split conflict instructions into separately executable command blocks. Resolve that overlap by keeping the simplified pull command from the base branch and preserving the literal multi-block recipe covered by the stacked tests.
The pre-pushed base merge leaves the user's local branch strictly behind origin, so the pull is always a fast-forward and the flag is a no-op in the expected case. Plain `git pull` is one less thing in the recipe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The helper checked that the conflict comment contains `git pull origin <branch>`, but that line is static text the action always emits, so the assertion only restated the script. The helper still runs the pull. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phlogistique
marked this pull request as ready for review
June 1, 2026 09:04
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.
Alternative to #32 for the same stuck-PR bug. Pick one.
Background: when a parent PR is squash-merged, the action brings each child branch up to date with three merges: the parent branch (the base-branch merge), the trunk as it stood just before the squash landed (
SQUASH_COMMIT~), and the squash itself recorded with-s oursso the child's diff against its new base stays clean. When the pre-squash trunk merge conflicts, the action asks the user to resolve, and a follow-up run triggered by the user's push finishes the job.Two separate bugs left a conflicting child PR broken:
SQUASH_COMMIT~conflict produced content that conflicts with the parent branch, the user's push left the head conflicting with its base. GitHub does not runpull_requestworkflows on a PR that conflicts with its base, so the follow-up run never fired and the PR was stuck for good.This PR fixes both:
continue_after_resolutionnow records the squash with-s oursand pushes before retargeting. The synchronize payload is the child PR, so the squash commit and new target are reconstructed from the merged parent PR (its merge commit and base).Pushing the base merge leaves the user's local branch behind origin, so the conflict comment now starts the recipe with
git pull --ff-only origin <branch>. Without it the user resolves on a stale head and the final push is rejected as non-fast-forward. The comment still lists only the genuine conflict to merge.The e2e conflict scenario already triggers this case (clean base merge, conflicting
SQUASH_COMMIT~merge), so coverage lives there: it checks the action pushed the base merge on top of the pre-conflict head and that the comment asks only for the genuine conflict, then resolves by following the comment verbatim (re-sync included) and checkscontinue_after_resolutionrecords the squash so the branch ends up mergeable into the new target.🤖 Generated with Claude Code