Deploy from Git
Last updated
Push your source and the platform builds and runs it. The first push creates the application; later pushes update it.
Requirements
- A
Dockerfileat the root of what you push. NotDockerfile.prod, notdocker/Dockerfile— that exact name, at the top level. If it's missing, the push is rejected with a message saying so, before any build starts. - Your repository's history. Shallow clones are rejected — see CI notes below.
Two branches, and the second one is the useful one
The push URL is shown in the panel (Add app → Advanced → Git Push) with credentials embedded in it. The branch you push to determines what happens:
| Push to | What happens |
|---|---|
deploy |
Build the image and apply it — your container is replaced |
build |
Build the image only — your running app is untouched |
| anything else | Nothing, with a message explaining why |
git push <push-url> HEAD:build # does it build?
git push <push-url> HEAD:deploy # ship it
HEAD:deploy pushes your current local branch to the remote deploy branch, whatever your branch is called locally.
Use build while you're iterating. Deploying replaces the container, which means a brief interruption, dropped connections and cleared in-memory state — none of which you want while you're finding out whether a Dockerfile line is correct.
Build output comes back over git
The build streams its output to your terminal as the push completes, so a failure is visible where you already are. If a build fails, that output is the first place to look; the app's logs cover the running container.
What the build does and doesn't get
- No environment variables and no build arguments. An
ARGwithout a default resolves to empty, and anything a framework inlines at build time won't have your values. See Configuration. - Limited memory and CPU — less than your app gets at runtime. A heavy asset build or compile can exceed it, usually failing part-way through with no clear error. Build in CI and push an image if that happens.
- The image is built for linux/amd64.
One push at a time
Pushes are processed one at a time per application, so two landing together will race and one will fail. In CI, use a concurrency group.
From CI
Store the push URL as a secret — it contains credentials that allow pushing code to your app, so treat it like a password.
The one thing that catches everyone: checkout actions usually default to a shallow clone, and a shallow push is rejected with shallow update not allowed. Set the full history (fetch-depth: 0 in GitHub Actions).
Push-only
The repository is a deploy target, not a code host. You cannot clone or fetch from it — keep your code in GitHub, GitLab, or your own Gitea, and push here to ship.
Troubleshooting
| Symptom | Cause |
|---|---|
| "You have just pushed to not tracked branch" | Push to deploy or build |
| "No Dockerfile found in the root of the pushed branch" | It's in a subfolder, or named something else |
shallow update not allowed |
Shallow clone in CI — fetch full history |
| Build stops part-way with no error | Out of memory — build in CI instead |
| Deploy succeeds, URL doesn't respond | App is listening on 127.0.0.1 — bind 0.0.0.0 |