Run scripts when git fetch finds new commits to specified git branches
As the deploy user (we use my-app-user in this document), install fetch-runner with uv:
uv tool install git+https://github.com/BYU-ODH/fetch-runnerNote the path of the installed executable (typically something like
/home/my-app-user/.local/bin/fetch-runner). You will need it in step 4.
Copy examples/deploy.sh from this repository into your app's directory:
cp /path/to/fetch-runner/examples/deploy.sh /srv/myapp/deploy.sh
chmod +x /srv/myapp/deploy.shOpen the script and replace every occurrence of deploy-user with the
username that runs your app's deployments (e.g. my-app-user). The guard block
at the top of the script prevents accidental execution as the wrong user or
as root.
Consider committing this script to your app's repository so the deploy procedure is version-controlled alongside the code it deploys.
Copy the example config to the deploy user's home directory and edit it:
cp /path/to/fetch-runner/examples/jobs.toml /home/my-app-user/jobs.tomlEdit /home/my-app-user/jobs.toml:
- Set
userunder[general]to the deploy user (e.g."my-app-user"). fetch-runner exits at startup if the running user does not match this value. - Set
poll_interval_secondsto how often fetch-runner should check for new commits (default:60). - For each
[[jobs]]entry, set:name— a human-readable label shown in logspath— absolute path to the local git repository to pollbranch— the branch to watch (e.g."main"or"production")script— absolute path to the script to run when new commits are found (e.g./srv/myapp/deploy.sh)timeout_seconds— how long to let the script run before killing it (optional; omit to use the default)
Copy the example unit file to systemd's unit directory:
sudo cp /path/to/fetch-runner/examples/fetch-runner.service \
/etc/systemd/system/fetch-runner.serviceEdit /etc/systemd/system/fetch-runner.service and update the lines in the
CUSTOMIZE block:
User/Group— set both to your deploy user (must matchuserinjobs.toml).ExecStart— replace/usr/local/bin/fetch-runnerwith the full path to the executable you noted in step 1, then replace/etc/fetch-runner/jobs.tomlwith the path to the config file from step 3. For example:ExecStart=/home/my-app-user/.local/bin/fetch-runner /home/my-app-user/jobs.tomlReadWritePaths— list every directory your deploy scripts need to write to (at minimum, the parent directories of your git repositories). Space-separate multiple paths, e.g.:ReadWritePaths=/srv/myapp /srv/anotherapp
Reload systemd and enable the service:
sudo systemctl daemon-reload
sudo systemctl enable --now fetch-runnerCheck whether the service is running and see its recent log output:
systemctl status fetch-runnerStream the full journal for the service (most useful when a deployment fails):
journalctl -u fetch-runner -fTo review all logs since the service last started:
journalctl -u fetch-runner -b