Fast, concurrent GitHub PR merger with watch mode.
export GITHUB_TOKEN=your_token_here
go install github.com/alileza/ghmerger@latest
# Merge PRs from stdin
echo "https://github.com/owner/repo/pull/123" | ghmerger merge
# Watch and auto-merge until timeout
ghmerger merge --watch --file prs.txtThe main command for merging PRs with status checking.
| Flag | Default | Description |
|---|---|---|
--watch, -w |
false | Watch mode: continuously attempt merges every 5s |
--file, -f |
stdin | Read PR URLs from file |
--concurrency, -c |
100 | Max concurrent GitHub API requests |
--timeout, -t |
1m | Global timeout (e.g., 30s, 5m, 1h) |
Normal mode: Try to merge each PR once, skip if already merged Watch mode: Live dashboard, retry merges every 5 seconds until all merged or timeout
- Stdin:
echo "URL" | ghmerger merge - File:
ghmerger merge --file prs.txt - Args:
ghmerger merge URL1 URL2
# Basic merge
ghmerger merge --file prs.txt
# Watch mode with 5min timeout
ghmerger merge --watch --timeout 5m --file prs.txt
# High concurrency merge
ghmerger merge --concurrency 200 --file prs.txt
# Watch from stdin
cat prs.txt | ghmerger merge --watchNormal mode:
✅ PR #123 (owner/repo) - already merged - Fix bug
✅ PR #124 (owner/repo) - merged - Add feature
❌ PR #125 (owner/repo) - error - not mergeable
Watch mode:
PR Status (Updated: 17:40:40)
================================================================================
✅ PR #123 (owner/repo) - closed - Fix bug
🟡 PR #124 (owner/repo) - open - Add feature (last try: 17:40:35)
❌ PR #125 (owner/repo) - open - Needs review
Quick status check without merging.
ghmerger status --file prs.txt
# Output: ✅🟡❌ PR #123 (owner/repo) - state - title# prs.txt - comments and empty lines ignored
https://github.com/owner/repo/pull/123
https://github.com/owner/repo/pull/124
- ✅ Merged/successfully merged
- 🟡 Ready to merge (open + mergeable)
- ❌ Cannot merge (conflicts/closed/error)
Use the GitHub Action to merge PRs in your workflows:
name: Merge PRs
on:
workflow_dispatch:
inputs:
pr_urls:
description: 'PR URLs (comma, space, or newline separated)'
required: true
default: 'https://github.com/owner/repo/pull/123, https://github.com/owner/repo/pull/124'
jobs:
merge-prs:
runs-on: ubuntu-latest
steps:
- uses: alileza/ghmerger@main
with:
pr-urls: ${{ github.event.inputs.pr_urls }}
github-token: ${{ secrets.GITHUB_TOKEN }}
timeout: '10m'
concurrency: '50'| Input | Description | Required | Default |
|---|---|---|---|
pr-urls |
PR URLs to merge (comma, space, or newline separated) | ✅ | - |
github-token |
GitHub token with repo permissions | ✅ | - |
timeout |
Max time to wait for merges (e.g., 5m, 1h) |
❌ | 10m |
concurrency |
Number of concurrent merge attempts | ❌ | 100 |
All these formats are supported:
# Comma separated
pr-urls: 'https://github.com/owner/repo/pull/123, https://github.com/owner/repo/pull/124'
# Space separated
pr-urls: 'https://github.com/owner/repo/pull/123 https://github.com/owner/repo/pull/124'
# Newline separated
pr-urls: |
https://github.com/owner/repo/pull/123
https://github.com/owner/repo/pull/124
# Mixed (any combination)
pr-urls: |
https://github.com/owner/repo/pull/123,
https://github.com/owner/repo/pull/124 https://github.com/owner/repo/pull/125| Output | Description |
|---|---|
merged-count |
Number of PRs successfully merged |
failed-count |
Number of PRs that failed to merge |
summary |
Summary of merge results |
The action also automatically creates a GitHub Actions Step Summary with:
- 📊 Overall statistics and success rate
- 🔧 Configuration details (timeout, concurrency)
- 📋 Detailed table of all PR results with status icons
- 🎉 Success/failure message
name: Auto-merge Dependabot PRs
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
jobs:
find-and-merge:
runs-on: ubuntu-latest
steps:
- name: Find Dependabot PRs
id: find-prs
run: |
# Get all open dependabot PRs (space separated)
prs=$(gh pr list --author "app/dependabot" --json url --jq -r '.[].url' | tr '\n' ' ')
echo "pr-urls=$prs" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Merge Dependabot PRs
uses: alileza/ghmerger@main
with:
pr-urls: ${{ steps.find-prs.outputs.pr-urls }}
github-token: ${{ secrets.GITHUB_TOKEN }}
timeout: '15m'
- name: Report Results
run: |
echo "✅ Merged: ${{ steps.merge.outputs.merged-count }} PRs"
echo "❌ Failed: ${{ steps.merge.outputs.failed-count }} PRs"
echo "📊 Summary: ${{ steps.merge.outputs.summary }}"export GITHUB_TOKEN=ghp_xxx # Required: GitHub token with repo access