Automate changes across multiple Git repositories — create branches, apply patches, push, and open merge requests in batch.
You need to apply the same change to 20 repositories. Manually that means: clone, branch, edit, commit, push, create merge request — times 20.
Maybe you need to rename a file in every repo, replace a deprecated URL in all docs, add a package to all projects or run a migration script. Nothing a plain Git patch file could solve, but something that can be automated with a script.
Patchbot does the repetitive parts for you. Write the change once as a patch script, point Patchbot at your repositories, and let it create feature branches, commit, push, and optionally open merge requests — across all of them.
Saving time, preventing careless mistakes and avoiding monotonous work.
Take a look at this blog post with real world examples to see how Patchbot helps reduce technical debt across Git repositories.
- Batch git operations - Apply the same patch to 1, 20, or 300 repositories
- Auto-discovery - Scan a GitLab namespace to find all repositories automatically
- Merge request creation - Optionally create GitLab MRs after pushing (
--create-mr) - Repository filtering - Target specific repos by path pattern or GitLab topic (
--filter) - Dry-run mode - Preview what would happen without making changes (
--dry-run) - Custom git user - Push as a bot user instead of your personal account
- CI-ready - Run Patchbot as a scheduled GitLab CI pipeline
# Create a new patch project using the skeleton
composer create-project pixelbrackets/patchbot-skeleton my-patches
cd my-patches
# Create a new patch
./vendor/bin/patchbot create "My first patch"
# Edit the patch script and commit message
# patches/my-first-patch/patch.php
# patches/my-first-patch/commit-message.txt
# Apply the patch to a repository
./vendor/bin/patchbot patch my-first-patch git@gitlab.com:user/repo.git- PHP
- Git
Use the skeleton package to create a patch project right away:
composer create-project pixelbrackets/patchbot-skeleton my-patchesOr install Patchbot as a dependency in an existing project:
composer require pixelbrackets/patchbotThe user running Patchbot needs clone and push access to the target repositories. SSH is the recommended protocol. See the walkthrough guide for details on configuring access.
Patchbot organizes patches in the patches/ directory. Each patch directory
contains a PHP script (patch.php) and a commit message (commit-message.txt):
patches/
|-- template/
| |-- commit-message.txt
| `-- patch.php
`-- update-changelog/
|-- commit-message.txt
`-- patch.php
The patch script runs in the root directory of the cloned target repository.
You can develop it incrementally by running php <path-to-patch>/patch.php
directly in any project directory.
./vendor/bin/patchbot patch <patch-name> <repository-url>Patchbot clones the repository, creates a feature branch, runs the patch script, commits the changes, and pushes the branch to the remote.
# Apply patch "template" to a repository
./vendor/bin/patchbot patch template git@gitlab.com:user/repo.git
# Preview without making changes
./vendor/bin/patchbot patch template git@gitlab.com:user/repo.git --dry-run
# Create a GitLab merge request after pushing
./vendor/bin/patchbot patch template git@gitlab.com:user/repo.git --create-mr
# Use a custom source branch (default: main)
./vendor/bin/patchbot patch template git@gitlab.com:user/repo.git --source-branch=development
# Use a custom feature branch name
./vendor/bin/patchbot patch template git@gitlab.com:user/repo.git --branch-name=feature-1337
# Pause before committing (for manual review)
./vendor/bin/patchbot patch template git@gitlab.com:user/repo.git --halt-before-commitApply a patch to all repositories listed in repositories.json:
./vendor/bin/patchbot patch-many <patch-name># Apply to all repositories
./vendor/bin/patchbot patch-many update-changelog
# Filter by path pattern
./vendor/bin/patchbot patch-many update-changelog --filter="path:my-org/*"
# Filter by GitLab topic
./vendor/bin/patchbot patch-many update-changelog --filter="topic:php"
# Combine filters, create MRs, and preview first
./vendor/bin/patchbot patch-many update-changelog --filter="topic:php" --create-mr --dry-runAfter batch processing completes, a summary shows how many repositories were patched, skipped, or failed.
Instead of adding repository URLs manually, let Patchbot discover them from a GitLab namespace (group or user):
# Set up your GitLab token in .env
cp .env.example .env
# Edit .env with your GITLAB_TOKEN and GITLAB_NAMESPACE
# Discover repositories
./vendor/bin/patchbot discover
# Or specify the namespace directly
./vendor/bin/patchbot discover --gitlab-namespace=mygroup
# Overwrite existing repositories.json
./vendor/bin/patchbot discover --forceThis creates a repositories.json file with all discovered repositories,
including their clone URLs and default branches.
Patchbot creates feature branches by design, so changes can be reviewed and tested by CI before merging. Use the merge commands when ready:
# Merge a branch into a target branch for one repository
./vendor/bin/patchbot merge <source-branch> <target-branch> <repository-url>
# Merge a branch into the default branch for all repositories
./vendor/bin/patchbot merge-many <source-branch># Examples
./vendor/bin/patchbot merge feature-add-license main git@gitlab.com:user/repo.git
./vendor/bin/patchbot merge-many feature-add-phpcs-rules
./vendor/bin/patchbot merge-many feature-add-phpcs-rules --dry-run./vendor/bin/patchbot create "Add CHANGELOG file"This generates a patch directory with the required files. Edit patch.php
with your change logic and commit-message.txt with the commit message.
See the walkthrough guide for tips
on developing and testing patches.
Commands
| Command | Description |
|---|---|
patch |
Apply changes, commit, push |
patch-many |
Apply a patch to all repositories |
merge |
Merge one branch into another, push |
merge-many |
Merge a branch into all repositories |
create |
Create a new patch |
discover |
Discover repositories from a GitLab namespace |
Options
| Option | Available in | Description |
|---|---|---|
--dry-run |
patch, merge, patch-many, merge-many | Preview without making changes |
--create-mr |
patch, patch-many | Create GitLab merge request after pushing |
--filter |
patch-many, merge-many | Filter repositories by path:glob or topic:name |
--source-branch |
patch | Base branch for the feature branch (default: main) |
--branch-name |
patch, patch-many | Custom name for the feature branch |
--halt-before-commit |
patch, patch-many | Pause before committing for manual review |
--force |
discover | Overwrite existing repositories.json |
-v / -vvv |
all | Increase output verbosity |
By default, commits use your system Git configuration. To push as a bot user, set these environment variables:
BOT_GIT_NAME="Patchbot"
BOT_GIT_EMAIL="patchbot@example.com"Run Patchbot as a scheduled GitLab CI pipeline instead of locally.
Copy .gitlab-ci.example.yml to your config repository and set the CI/CD
variables GITLAB_TOKEN and GITLAB_NAMESPACE.
https://gitlab.com/pixelbrackets/patchbot/
Mirror https://github.com/pixelbrackets/patchbot/
GNU General Public License version 2 or later
The GNU General Public License can be found at http://www.gnu.org/copyleft/gpl.html.
Dan Kleine (mail@pixelbrackets.de / @pixelbrackets)
See CHANGELOG.md
This script is Open Source, so please use, share, patch, extend or fork it.
Contributions are welcome!
Please send some feedback and share how this package has proven useful to you or how you may help to improve it.