From 4e13f7a27c97fc224a1c9bb1b15b94b135e40a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Rubinstein?= Date: Mon, 1 Jun 2026 17:52:13 +0200 Subject: [PATCH 1/2] Reference the merged PR by number in the conflict comment The "I tried to merge ... into this branch" sentence named the raw branch ref. Render it as a "#N" reference that GitHub links to the merged PR; the pre-squash trunk state has no PR, so it stays a backticked commit. The bash recipe is unchanged and still uses the raw ref that git merge needs. Co-Authored-By: Claude Opus 4.8 (1M context) --- update-pr-stack.sh | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/update-pr-stack.sh b/update-pr-stack.sh index c000f41..32cda12 100755 --- a/update-pr-stack.sh +++ b/update-pr-stack.sh @@ -45,14 +45,33 @@ has_squash_commit() { && git merge-base --is-ancestor SQUASH_COMMIT "$BRANCH" } -format_branch_list_for_text() { +# Render a conflict ref for prose. When the ref is a branch that has a pull +# request, emit a "#N" reference that GitHub turns into a link; otherwise emit +# the ref in backticks (the pre-squash trunk state is a bare commit with no PR). +# The bash recipe still uses the raw ref, which `git merge` needs. +format_conflict_ref_for_text() { + local ref="$1" + local branch="${ref#origin/}" + if [[ "$branch" != "$ref" ]]; then + local number + number=$(gh pr list --head "$branch" --state merged --json number --jq '.[0].number // ""' 2>/dev/null || true) + if [[ -n "$number" ]]; then + printf '#%s' "$number" + return + fi + fi + printf '`%s`' "$ref" +} + +format_conflict_list_for_text() { + local separator for ((i=1; i<=$#; i++)); do case $i in - 1) format='`%s`';; - $#) format=', and `%s`';; - *) format=', `%s`';; + 1) separator='';; + $#) separator=', and ';; + *) separator=', ';; esac - printf "$format" "${!i}" + printf '%s%s' "$separator" "$(format_conflict_ref_for_text "${!i}")" done } @@ -107,7 +126,7 @@ update_direct_target() { echo "### ⚠️ Automatic update blocked by merge conflicts" echo echo -n "I tried to merge " - format_branch_list_for_text "${CONFLICTS[@]}" + format_conflict_list_for_text "${CONFLICTS[@]}" echo " into this branch while updating the pull request stack and hit conflicts." echo echo "#### How to resolve" From 0d4cdddf809774638e6bffbd7fab38a2aeb30c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Rubinstein?= Date: Mon, 1 Jun 2026 17:55:56 +0200 Subject: [PATCH 2/2] Use the merged PR number from the event payload, not a gh lookup The first cut resolved the parent PR with `gh pr list --head`. The squash-merge event already carries `pull_request.number`, so pass it through as MERGED_PR_NUMBER and reference it directly. The conflict-resolved path, which reconstructs the parent from the synchronize payload, picks the number up from the same lookup it already runs. Co-Authored-By: Claude Opus 4.8 (1M context) --- action.yml | 1 + update-pr-stack.sh | 36 ++++++++++++++++-------------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/action.yml b/action.yml index 4eb9363..61f9e4c 100644 --- a/action.yml +++ b/action.yml @@ -52,6 +52,7 @@ runs: ACTION_MODE: ${{ steps.check.outputs.mode }} SQUASH_COMMIT: ${{ github.event.pull_request.merge_commit_sha }} MERGED_BRANCH: ${{ github.event.pull_request.head.ref }} + MERGED_PR_NUMBER: ${{ github.event.pull_request.number }} TARGET_BRANCH: ${{ github.event.pull_request.base.ref }} PR_BRANCH: ${{ github.event.pull_request.head.ref }} run: | diff --git a/update-pr-stack.sh b/update-pr-stack.sh index 32cda12..2161f6d 100755 --- a/update-pr-stack.sh +++ b/update-pr-stack.sh @@ -45,22 +45,18 @@ has_squash_commit() { && git merge-base --is-ancestor SQUASH_COMMIT "$BRANCH" } -# Render a conflict ref for prose. When the ref is a branch that has a pull -# request, emit a "#N" reference that GitHub turns into a link; otherwise emit -# the ref in backticks (the pre-squash trunk state is a bare commit with no PR). -# The bash recipe still uses the raw ref, which `git merge` needs. +# Render a conflict ref for the prose. The merged parent branch is shown as a +# "#N" reference that GitHub links to its PR (MERGED_PR_NUMBER comes straight +# from the event payload); the pre-squash trunk state is a bare commit with no +# PR, so it stays in backticks. The bash recipe still uses the raw ref, which +# `git merge` needs. format_conflict_ref_for_text() { local ref="$1" - local branch="${ref#origin/}" - if [[ "$branch" != "$ref" ]]; then - local number - number=$(gh pr list --head "$branch" --state merged --json number --jq '.[0].number // ""' 2>/dev/null || true) - if [[ -n "$number" ]]; then - printf '#%s' "$number" - return - fi + if [[ "$ref" == "origin/$MERGED_BRANCH" && -n "${MERGED_PR_NUMBER:-}" ]]; then + printf '#%s' "$MERGED_PR_NUMBER" + else + printf '`%s`' "$ref" fi - printf '`%s`' "$ref" } format_conflict_list_for_text() { @@ -215,13 +211,13 @@ continue_after_resolution() { echo "Current base branch: $OLD_BASE" # The synchronize payload is the child PR, so SQUASH_COMMIT / MERGED_BRANCH / - # TARGET_BRANCH from the original squash-merge run are not in the environment. - # Reconstruct them from the merged parent PR: OLD_BASE is the parent branch, - # and the merged PR whose head is OLD_BASE gives the new target (its base) and - # the squash commit (its merge commit). - local NEW_TARGET SQUASH_HASH - read -r NEW_TARGET SQUASH_HASH < <(gh pr list --head "$OLD_BASE" --state merged \ - --json baseRefName,mergeCommit --jq '.[0] | "\(.baseRefName // "") \(.mergeCommit.oid // "")"') + # TARGET_BRANCH / MERGED_PR_NUMBER from the original squash-merge run are not + # in the environment. Reconstruct them from the merged parent PR: OLD_BASE is + # the parent branch, and the merged PR whose head is OLD_BASE gives the new + # target (its base), the squash commit (its merge commit), and its number. + local NEW_TARGET SQUASH_HASH MERGED_PR_NUMBER + read -r NEW_TARGET SQUASH_HASH MERGED_PR_NUMBER < <(gh pr list --head "$OLD_BASE" --state merged \ + --json baseRefName,mergeCommit,number --jq '.[0] | "\(.baseRefName // "") \(.mergeCommit.oid // "") \(.number // "")"') if [[ -z "$NEW_TARGET" || -z "$SQUASH_HASH" ]]; then echo "⚠️ Could not find where '$OLD_BASE' was merged to; skipping base branch and deletion updates"