- Multi-Repository Support (Process PRs across accessible repositories, and organizations(1))
- Filtering Capabilities (Filter PRs by base branch, ex/include labels(2), title prefix, and repo owner)
- Merge Readiness Evaluation (Check CI status, and code review approvals before merging)
- Flexible Merge Methods (Support merge, rebase, and squash (3))
- Bypass Option (Bypass required review count (4))
- Dry-Run Mode (Preview which PRs would be merged without performing the actual merge)
Notes
- Multiple organizations access requires Classic Personal Access Token.
- In filtering PRs,
exclude-labelsis applied first, followed byinclude-labels.- Review repository | settings | pull requests on allowed PR merge strategies.
- The token owner must be allowed to bypass rule to merge PR.
Set up a GitHub personal access token (PAT) with the required permissions.
| Token Type | Required Permissions | Notes |
|---|---|---|
| Classic PAT | repo scope (full) |
Supports multi-organization access |
| Fine-grained PAT | Repository: Read & Write on Contents and Pull Requests |
Limited to single organization access |
Notes
- If you are using GitHub Actions, the default
GITHUB_TOKENlacks the admin permissions needed to read branch protection settings.- GitHub Apps do not support GitHub REST API endpoints /users and /user/repos. Thus, we only support the use of classic and fine-grained personal access token.
| Option | Description | Default |
|---|---|---|
base-branch |
merge the head branch to the base branch | main |
bypass-review-count |
bypass required review count rule | false |
dry-run |
preview (true); merge (false) | true |
exclude-labels |
filter out PRs from processing (comma/space separated) | "" |
include-labels |
filter in PRs to process (comma/space separated) | "" |
merge-method |
merge strategy: merge, rebase, or squash | merge |
owner |
filter repos to specific user/org | "" |
prefix |
filter PRs with title prefix | "" |
repo-type |
filter repo types: all, private, or public | all |
Use this tool as a GitHub Action in your workflow file. An example workflow below:
- Runs
on scheduleat3:30 AM UTC (Monday-Friday)oron demand. - Configures
merge-pullsto:bypass-review-count- bypass required review count.dry-run- perform actual merge.exclude-labels- filter out PRs withstaleortestlabels.include-labels- filter in PRs withdependencieslabels.- use default values for the rest of the options.
---
name: merge-pulls
on:
schedule:
- cron: "30 3 * * 1-5"
workflow_dispatch:
permissions:
contents: read
pull-requests: read
jobs:
merge-pulls:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Run merge-pulls # https://github.com/marketplace/actions/merge-pulls
uses: tagdots/merge-pulls@<commit sha> # <version>
env:
GH_TOKEN: ${{ secrets.SECRET_GITHUB_PAT }}
with:
# override default
bypass-review-count: true
dry-run: false
exclude-labels: "stale,test"
include-labels: "dependencies"
# # defaults
# base-branch: "main"
# merge-method: "merge"
# owner: ""
# prefix: ""
# repo-type: "all"
Use this as CLI tool in a Python virtual environment. An example below:
- Installs
merge-pulls. - Exports
GH_TOKENenvironment variable (classic PAT). - Runs
merge-pullson pull requests that hasdependenciesormerge-readylabel. - Merges 4 of 6 open pull requests.
1. ~/work/<your project> $ uv pip install -U merge-pulls
2. ~/work/<your project> $ export GH_TOKEN="ghp_xxxxxxxxxxxxx"
3. ~/work/<your project> $ merge-pulls --include-labels "merge-ready,dependencies" --dry-run false
🚀 Starting Merge-Pulls (1.0.0)
📚 Loading configuration from: ./config/default.yaml
📚 Configuration (merged YAML and CLI):
base-branch: main
bypass-review-count: False
dry-run: False
exclude-labels: set()
include-labels: { 'dependencies', 'merge-ready' }
merge-method: merge
owner:
prefix:
repo-type: all
✅ Token Owner User Information :: login = Jack Nolan, Org. Access = ['org1', 'org2']
✅ Finding Open Pull Request...
▪ PR: https://github.com/org1/helloworld/pulls/101 (title: [GITHUB-ACTIONS] Bump the github-actions group with 7 updates)
▪ PR: https://github.com/org1/dotfiles/pulls/34 (title: [UV] Bump the uv group with 2 updates)
▪ PR: https://github.com/org1/dotfiles/pulls/35 (title: fix: memory leak caused by loop)
▪ PR: https://github.com/org2/rainer/pulls/21 (title: feat: add new CLI option)
▪ PR: https://github.com/org2/tac/pulls/2 (title: [PIP] Bump the pip group with 1 updates)
▪ PR: https://github.com/org2/tac/pulls/3 (title: refactor: generator expression)
Total Number of Open PR :: 6
✅ Finding PR Ready For Merge...
▪ Repo: org1/dotfiles (PR #34) -> Mergeable: True, Rebaseable: True, CI status checks: ok-for-merge, Approval Review checks: ok-for-merge
▪ Repo: org1/dotfiles (PR #35) -> Mergeable: True, Rebaseable: True, CI status checks: ok-for-merge, Approval Review checks: ok-for-merge
▪ Repo: org2/rainer (PR #21) -> Mergeable: True, Rebaseable: True, CI status checks: ok-for-merge, Approval Review checks: ok-for-merge
▪ Repo: org2/tac (PR #2) -> Mergeable: True, Rebaseable: False, CI status checks: ok-for-merge, Approval Review checks: ok-for-merge
Total Number of Mergeable PR :: 4
✅ Final Merged Open PR Info...
▪ PR: https://github.com/org1/dotfiles/pulls/34 (title: [UV] Bump the uv group with 2 updates)
▪ PR: https://github.com/org1/dotfiles/pulls/35 (title: fix: memory leak caused by loop)
▪ PR: https://github.com/org2/rainer/pulls/21 (title: feat: add new CLI option)
▪ PR: https://github.com/org2/tac/pulls/2 (title: [PIP] Bump the pip group with 1 updates)
Total Number of Merged PR :: 4
🎉 Merge-Pulls Summary :: {'open-prs': 6, 'mergeable-prs': 4, 'merged-prs': 4}
Open an issue
See Contributing
This project is licensed under the MIT License - see the LICENSE file for details.
If you find this project helpful, please ⭐ star it. Thank you.
User access token by GitHub App => 403