This guide walks you through a typical Patchbot workflow — from setting up access, writing your first patch, applying it to repositories, and running Patchbot in CI. For a quick overview see the README.
The user running Patchbot needs to be allowed to clone and push to all target repositories.
Patchbot supports all protocols that Git supports natively: FILE, HTTP/HTTPS, SSH. The recommended protocol is SSH.
Git by default does not store any credentials. So every connection to a repository by HTTPS will prompt for a username and password.
To avoid these password prompts when using HTTPS URIs with Patchbot you have two options:
- Allow Git to store credentials in memory for some time
- The password prompt then pops up once only for each host
- Example command to keep the credentials in memory for 15 minutes:
git config --global credential.helper 'cache --timeout=900'
- Force Git to use SSH protocol checkouts instead of HTTP/HTTPS
- Has to be configured for each host
- Example commands to set up the replacements for GitHub, GitLab & BitBucket:
git config --global url."ssh://git@github.com/".insteadOf "https://github.com/" git config --global url."ssh://git@gitlab.com/".insteadOf "https://gitlab.com/" git config --global url."ssh://git@bitbucket.org/".insteadOf "https://bitbucket.org/"
If you don't use PHP, download the standalone binary from GitHub Releases and create a project directory manually:
# Download binary
curl -L -o patchbot https://github.com/pixelbrackets/patchbot-dist/releases/latest/download/patchbot-linux-x64
chmod +x patchbot
# Create project structure
mkdir -p my-patches/patches
cd my-patches
# Create your first patch
../patchbot create "My first patch" --type=shThe binary bundles the PHP runtime, so no PHP installation is needed on your system. Write patches in Shell, Python, or as Git diffs.
The easiest way to get started is the skeleton package:
composer create-project pixelbrackets/patchbot-skeleton my-patches
cd my-patchesThis gives you a ready-made project structure:
my-patches/
|-- composer.json
|-- patches/
| `-- template/
| |-- commit-message.txt
| `-- patch.php
`-- .editorconfig
Browse the patchbot-examples repository for ready-to-use patches you can import and customize.
To create a new patch from scratch, use the interactive wizard:
./vendor/bin/patchbot createOr provide the name and optionally the type directly:
# Creates a PHP patch (default)
./vendor/bin/patchbot create "Add CHANGELOG file"
# Creates a Shell patch
./vendor/bin/patchbot create "Add CHANGELOG file" --type=shThis generates patches/add-changelog-file/ with two files to edit:
- The patch file (e.g.
patch.php,patch.sh) - The script that makes the actual changes commit-message.txt- The commit message used when applying the patch
Patchbot detects the patch type by filename. The create command generates
the correct file based on the selected type:
| File | Language | Execution |
|---|---|---|
patch.php |
PHP | php patch.php |
patch.sh |
Shell | bash patch.sh |
patch.diff |
Git diff | git apply patch.diff |
patch.py |
Python | python3 patch.py |
Each patch directory must contain exactly one patch file. Using multiple patch
files in the same directory (e.g. both patch.php and patch.sh) is not
allowed and will result in an error.
Patchbot runs the patch script isolated in the root directory of the cloned target repository. This means you can develop the script incrementally by running it directly in any project directory:
cd /path/to/some-project
php /path/to/my-patches/patches/add-changelog-file/patch.php
# or
bash /path/to/my-patches/patches/add-changelog-file/patch.shCheck the result, adjust the script, repeat. When the patch works as expected, use Patchbot to distribute it.
A patch script should be safe to run multiple times on the same repository.
If the change was already applied, the script should skip gracefully and
exit with code 0 (success). Patchbot detects "nothing to change" by
checking git status after the script runs — if no files changed, the
repository is skipped automatically.
Use a guard clause at the top of your script to exit early when the patch does not apply. Do not exit with an error code, since the patch was not needed rather than broken.
<?php
// PHP: exit early with success
if (file_exists('.editorconfig')) {
echo 'EditorConfig already exists, skipping' . PHP_EOL;
exit(0);
}#!/bin/bash
# Shell: exit early with success
if [ ! -f "composer.json" ]; then
echo "No composer.json found, skipping"
exit 0
fiApply the patch to a single repository:
./vendor/bin/patchbot patch add-changelog-file git@gitlab.com:user/repo.gitPatchbot will clone the repository, create a feature branch, run the patch script, commit the changes, and push the branch to the remote.
Use --dry-run to preview what would happen without making any changes:
./vendor/bin/patchbot patch add-changelog-file git@gitlab.com:user/repo.git --dry-runFor batch operations, Patchbot reads a repositories.json file that lists
all target repositories. You can generate it automatically or write it by hand.
# Set up your GitLab token in .env
cp .env.example .env
# Edit .env with your GITLAB_TOKEN and GITLAB_NAMESPACE
# Discover all repositories in a namespace
./vendor/bin/patchbot discover --gitlab-namespace=mygroupThis generates a repositories.json file with the following structure:
{
"generated": "manual",
"repositories": [
{
"path_with_namespace": "user/example-project",
"clone_url_ssh": "git@gitlab.com:user/example-project.git",
"clone_url_http": "https://gitlab.com/user/example-project.git",
"default_branch": "main",
"topics": []
}
]
}The topics field is populated from the GitLab project topics (Settings >
General > Topics). Repositories without topics get an empty array. You can
add custom topics manually to categorize repositories for filtering — for
example, add "topics": ["php", "internal"] to group repositories by
language or team.
Then apply the patch to all discovered repositories:
./vendor/bin/patchbot patch:many add-changelog-fileUse --filter to target specific repositories by path or topic:
# Only repositories matching a path pattern
./vendor/bin/patchbot patch:many add-changelog-file --filter="path:mygroup/typo3-*"
# Only repositories with a specific topic
./vendor/bin/patchbot patch:many add-changelog-file --filter="topic:php"After batch processing completes, a summary shows how many repositories were patched, skipped, or failed.
Patchbot always creates a feature branch rather than committing directly to existing branches. This way you can review the changes and let CI run tests before merging.
To create a GitLab merge request automatically, add --create-mr:
./vendor/bin/patchbot patch:many add-changelog-file --create-mrWhen ready to merge, use the merge commands:
# Merge a single repository
./vendor/bin/patchbot merge feature-add-changelog-file main git@gitlab.com:user/repo.git
# Merge across all repositories
./vendor/bin/patchbot merge:many feature-add-changelog-fileThe patchbot-examples repository contains ready-to-use patches you can import and customize.
Use the import command to import a patch from a Gist, a Git repository,
or a subdirectory within a repository:
# Import from a Gist
./vendor/bin/patchbot import https://gist.github.com/pixelbrackets/98664b79c788766e4248f16e268c5745
# Import with a custom name
./vendor/bin/patchbot import https://gist.github.com/pixelbrackets/98664b79c788766e4248f16e268c5745 --patch-name=my-find-replace
# Import from a Git repository subdirectory
./vendor/bin/patchbot import https://github.com/pixelbrackets/patchbot-examples --path=patches/add-editorconfig
# Import all patches from a Git repository
./vendor/bin/patchbot import https://github.com/pixelbrackets/patchbot-examplesThe command clones the source, copies the patch files into your patches/
directory, and removes the .git directory. Review and customize the
imported patch before applying it.
The patches in your project are probably specific to your organisation or domain. The best way to share them is to share the entire patch project as a Git repository.
To share a single general-purpose patch, use the export command. It
creates a GitHub Gist using the GitHub CLI
(or prints the command if gh is not installed):
./vendor/bin/patchbot export add-editorconfigSee this example patch
that adds an .editorconfig file to a repository.
Instead of running Patchbot locally, you can set it up as a scheduled GitLab CI pipeline:
- Copy
.gitlab-ci.example.ymlto.gitlab-ci.ymlin your config repository - Set CI/CD variables:
GITLAB_TOKEN,GITLAB_NAMESPACE - Trigger manually via GitLab UI (CI/CD > Pipelines > Run pipeline)
See the example configuration for details.
By default, commits use your system Git configuration. To push as a bot
user, set these environment variables (in .env or your shell):
BOT_GIT_NAME="Patchbot"
BOT_GIT_EMAIL="patchbot@example.com"Add -v to any command for more output, or -vvv for full debugging.
This will show all steps and Git commands applied by Patchbot.