listens for git webhooks and runs bash scripts when they arrive
Go to file
AJ ONeal c2085858a7 bugfix: remove extraneous return 2021-03-17 17:51:35 -06:00
.gitdeploy add .gitdeploy 2020-10-21 05:15:02 +00:00
assets add init to initialize ./scripts/ with examples 2020-10-23 15:56:49 -06:00
examples support pytest results 2021-02-25 19:52:40 -07:00
html Re: #12: update package-lock.json 2021-03-06 11:55:50 -07:00
internal bugfix: remove extraneous return 2021-03-17 17:51:35 -06:00
public git-deploy static server with basic options 2020-09-28 01:26:16 -06:00
vendor go-github v32 -> v33 2021-02-22 15:48:33 -07:00
.gitignore ignore test logs 2021-02-24 02:18:14 -07:00
.gitmodules work 2020-09-19 13:59:59 -04:00
.goreleaser.yml releaser: use -mod=vendor, not go mod download 2020-10-20 23:25:01 +00:00
.ignore add vendor/ to .ignore 2020-10-21 05:15:28 +00:00
.prettierignore build /api/admin/repos by walking scripts/ 2020-10-20 21:59:10 -06:00
.prettierrc run deploy scripts from within trusted repos 2020-10-20 22:44:31 -06:00
AUTHORS add exec script 2020-09-28 21:18:35 -06:00
LICENSE add exec script 2020-09-28 21:18:35 -06:00 support pytest results 2021-02-25 19:52:40 -07:00
bitbucket.go rename to gitdeploy 2020-10-09 09:22:06 +00:00
gitea.go rename to gitdeploy 2020-10-09 09:22:06 +00:00
github.go rename to gitdeploy 2020-10-09 09:22:06 +00:00
go.mod go-github v32 -> v33 2021-02-22 15:48:33 -07:00
go.sum go-github v32 -> v33 2021-02-22 15:48:33 -07:00
main.go add max job runtime 2021-03-17 13:10:38 -06:00
staticcheck.conf add staticcheck.conf 2021-03-15 18:06:28 -06:00


gitdeploy is an app for continuous deployment of static websites.

  1. Point a domain to a server running gitdeploy
  2. Set git webhooks (Github, Gitea, Bitbucket, etc)
  3. Create build & deploy scripts from the examples
  4. Profit (when you push, the build will kick off)


gitdeploy is intended for use with static websites that are generated after changes are pushed to a Git repository. This works with sites that are being edited in code and tracked in Git. Sites that have their content managed with a headless CMS that pushes to Git are also very well-suited.

gitdeploy supports verified webhooks from Github, Bitbucket, and Gitea.

gitdeploy is written in Go. This means that it's a standalone binary available on all major operating systems and architectures. It provides an API with endpoints that handle webhooks, allow for initiation of builds, and getting the status of builds and build jobs.

gitdeploy comes with a simple interface. The interface be disabled if you don't want to use it.


gitdeploy init
gitdeploy run --listen :3000 --scripts ./scripts/
Usage of gitdeploy run:
  -listen string
    	the address and port on which to listen (default :4483)
  -github-secret string
    	secret for github webhooks (same as GITHUB_SECRET=)
  -bitbucket-secret string
    	secret for bitbucket webhooks (same as BITBUCKET_SECRET=)
  -gitea-secret string
    	secret for gitea webhooks (same as GITEA_SECRET=)
  -scripts string
    	path to ./scripts/{,,etc}
  -trust-repos string
    	list of repos (ex: '', or '*' for all) for which to run '.gitdeploy/'
    	enable compression for text,html,js,css,etc (default true)
  -promotions string
    	a list of promotable branches in descending order (default 'production,staging,master')
  -serve-path string
    	path to serve, falls back to built-in web app
    	trust X-Forwarded-For header


You can download gitdeploy from the Github Releases API and place it in your PATH, or install it with Webi (

Mac, Linux:

curl -sS | bash

Windows 10:

curl -A MS | powershell

Manual Install


Git SSH Deploy Keys and Tokens

All of the clone URLs are HTTPS clone URLs.

To use SSH clone URLs, you should update your git credentials:

git config --global url."ssh://".insteadOf ""

This will add an entry like this to your .gitconfig:

[url "ssh://"]
    insteadOf =

For more info see The Git Credentials Cheat Sheet at

Setup with Deploy Scripts

Start by initializing your .env and ./scripts directory.

gitdeploy init

The default is sensible - if another exists in a directory with the same repo name as an incoming webhook, it runs it.

The example deploy scripts are a good start, but you'll probably need to update them to suit your build process for your project.

In-repo .gitdeploy scripts

A repo my have its own .gitdeploy/ at its root, but by default these are ignored.

You can set --trust-repos (or TRUST_REPOS) to allow deploy scripts to be run directly from a repository.

  • matches are case-insensitive (foo matches Foo)
  • a wildcard * may be used (at the end of a string) to define a prefix
  • the list may be space ' ' or comman , delimited
# trust a few repos to run their own deploy scripts
gitdeploy run --listen :3000 --trust-repos ''

# trust an organization
gitdeploy run --listen :3000 --trust-repos '*'

# trust all repos
gitdeploy run --listen :3000 --trust-repos '*'

Git Info

These ENVs are set before each script is run:




GET  /api/admin/jobs?since=1577881845.999

      "success": true,
      "jobs": [
            "id": "XXXXXXXXXXXX",
            "_job_id": "XXXXXXXXXXXX",                   // replaced with jobs[].id
            "started_at": "2020-01-01T12:30:45.999Z",
            "_created_at": "2020-01-01T12:30:45.999Z",   // replaced with jobs[].ref.timestamp
            "ref": {
                "repo_id": "",
                "timestamp": "2001-02-03T16:30:00.999Z",
                "https_url": "",
                "ssh_url": "",
                "rev": "abcdef7",
                "ref": "refs/heads/master",
                "ref_type": "branch",
                "ref_name": "master",
                "repo_owner": "example-org",
                "repo_name": "example-project"
            "ended_at": "2001-02-03T16:30:04.999Z",
            "exit_code": 0

POST /local/jobs/{job_id}?format=gitdeploy

    { "report":
        { "name": "sleep test",
          "status": "PASS",
          "message": "the top level result",
          "results": [
            { "name": "a sub test",
              "status": "PASS",
              "message": "a sub group",
              "_detail": { "foo": "bar" }

POST /local/jobs/{job_id}?format=pytest

    { "exitcode": 0,
      "root": "/home/app/srv/",
      "tests": [
        { "nodeid": "pytest::idthing",
          "outcome": "passed"

POST /api/admin/jobs
    { "job_id": "xxxx", "kill": true }

    { "success": true }

GET /api/admin/logs/{job_id}?since=1577881845.999

      "success": true,
      "started_at": "2001-02-03T16:30:01.999Z",
      "id": "",
      "ref": {
        "repo_id": "",
        "timestamp": "2001-02-03T16:30:00.999Z",
        "https_url": "",
        "ssh_url": "",
        "rev": "abcdef7",
        "ref": "refs/heads/master",
        "ref_type": "branch",
        "ref_name": "master",
        "repo_owner": "org",
        "repo_name": "repo"
      "ended_at": "2001-02-03T16:30:04.999Z",
      "exit_code": 0,
      "logs": [
          "timestamp": "2001-02-03T16:30:02.999Z",
          "stderr": false,
          "text": "Cloning into '/tmp/tmp.vksS1ln6Wv/repo'...\n"
          "timestamp": "2001-02-03T16:30:03.999Z",
          "stderr": false,
          "text": "Nothing to do for\n"

# note: see --help for how to use --promotions
POST /api/admin/promote

    { "clone_url": "https://...", "ref_name": "development" }

    { "success": true, "promote_to": "staging" }

# note: each webhook is different, but the result is to run a
POST /api/admin/webhooks/{github,gitea,bitbucket}



pushd html/
  npm ci


With GoReleaser:

goreleaser --snapshot --skip-publish --rm-dist

With Golang:

export GOFLAGS="-mod=vendor"

go run -mod=vendor
go generate -mod=vendor ./...
go build -mod=vendor .

You can use build tags to remove providers from the build:

go build -mod=vendor -tags nobitbucket,nogithub .

Supported tags are:

  • nogithub
  • nogitea
  • nobitbucket

Run as a System Service

sudo env PATH="$PATH" \
  serviceman add --name gitdeploy --system \
    --username app -path "$PATH" -- \
    gitdeploy run --scripts ./scripts/

Add Webhooks

To add a webhook you'll first need a secret

with node.js:


Then you'll need to set up the webhook in your platform of choice.


New Webhook:

Payload URL: https://YOUR_DOMAIN/api/webhooks/github
Content-Type: application/json
Which events would you like to trigger this webhook?
Just the `push` event.
Active: ✅


Sometimes Bitbucket does not give you the option to specify the (X-Hub-Signature) secret, so you'll have to append an access_token instead. Example:

Title: gitdeploy
URL: https://YOUR_DOMAIN/api/webhooks/bitbucket?access_token=YOUR_SECRET
Triggers: Repository push

Securing the Webook with HTTPS

I recommend using caddy to HTTPS: {
    log {
        output stdout
        format console
    encode gzip zstd
    reverse_proxy /* localhost:4483

How to Generate a Base64 Secret

in your browser:

(async function () {
  var rnd = new Uint8Array(16);
  await crypto.getRandomValues(rnd);
  var b64 = [].slice
    .map(function (ch) {
      return String.fromCharCode(ch);
  var secret = btoa(b64)
    .replace(/\//g, "_")
    .replace(/\+/g, "-")
    .replace(/=/g, "");;

with node.js:

  .replace(/\+/g, "-")
  .replace(/\//g, "_")
  .replace(/=/g, "");


Copyright 2020 The gitdeploy Authors

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at