Repository navigation
gh pr merge --auto -d does not delete the branch after merge #9073
Description
Activity
Reading the code this is intentional behaviour when you provide
--autobecause as far as I know there is no way to tell the API to remember to delete the branch when the PR is automatically merged.
Lines 448 to 450 in af02889
if !m.deleteBranch || m.crossRepoPR || m.autoMerge { return nil } However, it's not clear to me why we allow both of these flags to be provided at the same time if this is the behaviour, instead of erroring and saying "you can't do that". This seems to have been the behaviour since the
--autoflag was introduced. I agree with you that it is confusing.Reacted by Arcadiy IvanovIs the suggestion that we need to fail early if these confliction options are specified?
Reviewing the code, I see we have other places we're checking for mutually exclusive options:
Lines 129 to 136 in af02889
if err := cmdutil.MutuallyExclusive( "specify only one of `--auto`, `--disable-auto`, or `--admin`", opts.AutoMergeEnable, opts.AutoMergeDisable, opts.UseAdmin, ); err != nil { return err } Reading through the rest of the code,
m.deleteBranchis not derived directly from options:Lines 583 to 601 in af02889
func deleteBranchSurvey(opts *MergeOptions, crossRepoPR, localBranchExists bool) (bool, error) { if !opts.IsDeleteBranchIndicated { var message string if opts.CanDeleteLocalBranch && localBranchExists { if crossRepoPR { message = "Delete the branch locally?" } else { message = "Delete the branch locally and on GitHub?" } } else if !crossRepoPR { message = "Delete the branch on GitHub?" } return opts.Prompter.Confirm(message, false) } return opts.DeleteBranch, nil } - addedpriority-3Affects a small number of users or is largely cosmeticAffects a small number of users or is largely cosmeticand removedneeds-triageneeds to be reviewedneeds to be reviewed
on May 16, 2024 Is the suggestion that we need to fail early if these confliction options are specified?
Yes, I can't see any reason that we would want to proceed in this case. I can't see any code path that would allow for the branch to be deleted if
--autois provided.Is it possible to set the branch to be auto-deleted after it is auto-merged? Using the 'Merge when ready' button in the UI seems to allow that?
Yes, I can't see any reason that we would want to proceed in this case.
I think passing both
--autoand--delete-branchshould work like this:branch is not merged branch is already merged same as --autosame as --delete-branchthe issue occurs even when merge queue is enabled and
--auto --delete-branchare used together$ gh pr merge --auto --delete-branch https://github.com/foo/baz/pull/123 X Cannot use `-d` or `--delete-branch` when merge queue enabled Error: Process completed with exit code 1.
Hey @electriquo 👋
That error message is actually intentional and a feature to make
gh pr mergemore intelligent and compatible with merge queues. We cannot allow branch deletion with a merge queue because the branch must exist while it is processed through the merge queue. If we allow branch deletion with merge queues, usually the PR gets quietly kicked out of the merge queue and the PR quietly closed - which is a poor experience that we don't want to allow.For more information, this feature was implemented in #10074 and discussed in #7011
☝ This is likely the same solution we'll apply to this issue - early exit when the user requests branch deletions that would result in undesirable behavior.
Reacted by electriquo@BagToad: thanks. i was hoping that the request to delete branch will take happen asynchronously and only after if the merge was successful.
@BagToad: thanks. i was hoping that the request to delete branch will take happen asynchronously and only after if the merge was successful.
@electriquo I think the best way to achieve that async branch deletion is to enable the automatic branch deletion repo setting. This works more elegantly with merge queue.
Does that setting work for you?
I have enabled the automatic behavior but I have some 600 pull requests before I've enable it. Is there any CLI option to delete the branch like in the pull request page?
I have enabled the automatic behavior but I have some 600 pull requests before I've enable it. Is there any CLI option to delete the branch like in the pull request page?
@rafaelpirolla
A shell script I wrote to go back and delete branches from closed pull requests using the gh cli, note there is a commented out line that you can switch if you want to go back through the full history, otherwise there is a limit to check the last 20 days/100 prs (you can change either limit):#!/bin/bash # Check if the correct number of arguments are provided if [ "$#" -ne 1 ]; then echo "Usage: $0 owner/repo" exit 1 fi # Variables REPO="$1" # limit the number of closed pull requests to check recent=$(date -v -20d +%Y-%m-%d) limit=100 # switch to check all # prs=$(gh pr list --repo $REPO --state closed --json number,headRefName) prs=$(gh pr list --repo $REPO --state closed --limit $limit --search "closed:>=$recent" --json number,headRefName) # Iterate over each pull request echo "$prs" | jq -c '.[]' | while read -r pr; do pr_number=$(echo "$pr" | jq -r '.number') branch_name=$(echo "$pr" | jq -r '.headRefName') # Check if the branch exists if gh api "repos/$REPO/branches/$branch_name" > /dev/null 2>&1; then gh api -X DELETE "repos/$REPO/git/refs/heads/$branch_name" echo "PR #$pr_number deleted branch: $branch_name" fi doneReacted by Rafael Pirolla@AriehSchneier Thanks for the above script. I have improved on it considerably as follows:
The below does not require checking out the repository at all and does not iterate over branches checking each one but has a set subtraction, i.e. you have one operation to retrieve all branches, one iteration to retrieve all PR records and then one operation each to delete only PRs that have matching branch found.
- Get all the branches that match
auto-update.*and retrieve their heads putting them into a JSON looking like{"branches": ["branch1", "branch2"]} - Get all PRs putting them into JSON
{"prs": [{}, {}]} - Eliminate all PRS with
headRefNamefound in BRANCHES. - Delete the results branches.
This script filters by
auto-update-*but it's easy to eliminate.BRANCHES=$(git ls-remote $GITHUB_SERVER_URL/$GITHUB_REPOSITORY 'auto-update-*' 2>/dev/null | { grep -o 'refs/heads/auto-update-.*' || true; } | sed 's/refs\/heads\///' | jq -Rn '{branches: [inputs]}') PRS=$(gh -R $GITHUB_REPOSITORY pr list --state closed --limit 100000 --state closed --json number,headRefName --jq '{prs: .}') CLOSED_PRS_WITH_BRANCHES=$(jq -s 'add' <(echo "$BRANCHES") <(echo "$PRS") | jq -c '[.branches[] as $branches | .prs[] | select(.headRefName | IN($branches))]') echo "$CLOSED_PRS_WITH_BRANCHES" | jq -r '.[] | .headRefName' | while read -r branch_name; do gh api -X DELETE "repos/$GITHUB_REPOSITORY/git/refs/heads/$branch_name" echo "Deleted branch $branch_name" done
You can see how it worked here: https://github.com/karellen/karellen-llvm/actions/runs/13469255221/job/37640624891#step:2:28
Reacted by Rafael Pirolla- Get all the branches that match
@arcivanov Nice update to remove the requirement to test each branch individually (noting that it wasn't required to check the repo out in my original script).
I have tweaked my original script with your changes with a couple of minor tweaks.- I removed the
auto-update-filter (that seems specific to your case) - Its a script that takes the repo as an input
- I sorted the results so they run in order (minor change, just for cleanliness of the output really)
- It outputs the PR number and branch name (minor again)
#!/bin/bash # Check if the correct number of arguments are provided if [ "$#" -ne 1 ]; then echo "Usage: $0 owner/repo" exit 1 fi # Variables REPO="$1" GITHUB_SERVER_URL="https://github.com" # Get all branches BRANCHES=$(git ls-remote $GITHUB_SERVER_URL/$REPO 2>/dev/null | { grep -o 'refs/heads/.*' || true; } | sed 's/refs\/heads\///' | jq -Rn '{branches: [inputs]}') # Get all closed pull requests PRS=$(gh pr list --repo $REPO --state closed --limit 100000 --json number,headRefName --jq '{prs: .}') # Calculate difference CLOSED_PRS_WITH_BRANCHES=$(jq -s 'add' <(echo "$BRANCHES") <(echo "$PRS") | jq -c '[.branches[] as $branches | .prs[] | select(.headRefName | IN($branches))] | sort_by(.number)') # Iterate over each pull request echo "$CLOSED_PRS_WITH_BRANCHES" | jq -c '.[]' | while read -r pr; do pr_number=$(echo "$pr" | jq -r '.number') branch_name=$(echo "$pr" | jq -r '.headRefName') gh api -X DELETE "repos/$REPO/git/refs/heads/$branch_name" echo "PR #$pr_number deleted branch: $branch_name" doneReacted by Rafael PirollaReacted by Arcadiy Ivanov- I removed the
What do you think of:
- Instead of asking users for inputs, why not pull the necessary values from GitHub context or environment variables? At the very least, you could use them to set default values. The Context Dump action might come in handy for this.
- Have you thought about turning this into a public GitHub Action? That way, anyone could use it easily without extra setup. It could make things much more convenient for others.
I just hit this problem on gh version 2.50.0 (2024-05-29). I would think that this is a pretty difficult command because I'm unsure how
ghwould know when the PR was merged successfully (passes the checks) to delete the local branch. Perhaps the remote branch deletion is easier, but there's also a repo setting for that. My suggestion is to actually not allow this combination of commands.- added a commit that references this issue
on Jan 13, 2026 - added a commit that references this issue
on Jan 13, 2026 - added a commit that references this issue
on Jun 9, 2026 - added a commit that references this issue
on Jul 20, 2026
Describe the bug
A successful
gh pr merge --auto -ddoes not delete the branch after a successful merge. It's unclear whether it's GH CLI problem or GH API.Steps to reproduce the behavior
The PR in question that didn't have a branch auto-deleted is here: karellen/karellen-llvm#40
The branch was marked for auto-merge and auto-delete here: https://github.com/karellen/karellen-llvm/actions/runs/9048046223/job/24860694266#step:4:62 (line 61)
If this is not something that can be fixed in GH CLI and GH API the documentation update is necessary to note that it's not an expected behavior.
Expected vs actual behavior
Expected: PR auto-merge will be followed by auto-delete if delete is requested.
Actual: The PR is automatically merged but the branch remains.
Logs
Above in the action items.