git-deploy-ng
Push-based deployment over SSH — a community continuation of mislav/git-deploy, published on RubyGems as git-deploy-ng.
Deploy with a single git push:
git push production main
Only the person setting up deployment needs the gem on their machine. Production servers need bash and git only — no Ruby on the server.
- CLI: Same commands as upstream; v0.9.0 introduces minor compatibility changes — see Backwards compatibility and ROADMAP.md
- Ruby: 2.7+ on the setup machine (including 4.x)
- Auth: SSH public keys (password auth not supported)
See also: ROADMAP.md · CONTRIBUTING.md · AGENTS.md
Table of contents
- How it works
- Installation
- Initial setup
- Everyday deployments
- Init templates
- Deploy callbacks
- CLI reference
- Remote URL formats
- Restart recipes
- Multiple environments
- Migrating from mislav/git-deploy
- Which git-deploy?
- Troubleshooting
- Development
How it works
Developer machine Production server
───────────────── ─────────────────
git remote add production user@host:/app
git deploy setup -r production ──SSH──► mkdir /app, git init, install post-receive hook
git deploy init ──local► generate deploy/* callbacks in your repo
git push production main ──git──► post-receive hook runs deploy/after_push
git deploy setupcreates (or reuses) a git repository on the server and installs apost-receivehook.git deploy initgeneratesdeploy/callback scripts in your application repo — commit these.git push production <branch>updates the server working copy and runs callbacks.
The hook checks out the pushed branch, then executes scripts in deploy/. Output is appended to log/deploy.log on the server.
Installation
gem install git-deploy-ng
Do not add it to your app's Gemfile. One developer runs setup once per project/host.
Initial setup
1. Add a deploy remote
The remote name is arbitrary (production, staging, online, …):
git remote add production "user@example.com:/apps/mynewapp"
Use an absolute path (/apps/...) or a home-relative path (apps/mynewapp → $HOME/apps/mynewapp). See Remote URL formats.
2. Set up the server repository
git deploy setup -r production
This will:
- Create the deploy directory if missing
- Run
git init(skipped if.gitalready exists) - Install
post-receivefromlib/hooks/post-receive.sh - Configure the remote HEAD to match your current local branch (
mainormaster)
Options:
| Flag | Purpose |
|---|---|
-r production |
Required — git remote name (no default) |
--force / -f |
Overwrite an existing post-receive hook |
--shared / -g |
Shared repository (git init --shared) |
--sudo / -s |
Create deploy dir with sudo |
3. Generate deploy callbacks
git deploy init --template rails-passenger
Commit the generated deploy/ directory. Scripts run on the server during each deploy.
4. Push
git push production main
5. One-time server admin
On the server, configure your web server (nginx/Apache), database, environment variables, etc.
Everyday deployments
git push production main
Push the branch that is checked out on the remote (configured during setup). Teammates deploy with plain git push — they do not need the gem installed.
What the default Rails template does
On each deploy, deploy/after_push typically:
- Syncs git submodules
- Runs
deploy/before_restart(bundle install, migrations, asset precompile) - Runs
deploy/restart(app server restart) - Runs
deploy/after_restart(if present)
Customize everything by editing deploy/* in your repo.
Init templates
git deploy init --template <name>
| Template | Stack | Generated restart |
|---|---|---|
rails-passenger |
Rails + Passenger | touch tmp/restart.txt |
rails-puma |
Rails + Puma | pumactl restart (with Passenger fallback) |
php-composer |
PHP + Composer | PHP-FPM reload via systemd |
generic |
Any | No-op — edit manually |
rails-passenger is the default. Templates only affect new git deploy init runs; existing deploy/ scripts are never overwritten unless files are missing.
If ./deploy exists as a file (not a directory), init aborts with an error. If deploy/ is non-empty, existing files are preserved.
Deploy callbacks
All scripts live in deploy/ at the repo root. They are ordinary executables (shell, Ruby, anything). All are optional.
| Script | When it runs |
|---|---|
deploy/setup |
First push to a new branch |
deploy/after_push |
Every subsequent push |
deploy/before_restart |
Called from after_push |
deploy/restart |
Called from after_push |
deploy/after_restart |
Called from after_push |
deploy/rollback |
git deploy rollback (instead of after_push) |
Hook entry point: lib/hooks/post-receive.sh (installed to .git/hooks/post-receive on the server).
CLI reference
All commands that connect to a server require -r <remote>. There is no default remote.
Global options:
| Option | Description |
|---|---|
-r, --remote |
Git remote name (required for remote commands) |
-n, --noop |
Print commands without executing |
| Command | Description |
|---|---|
git deploy init [--template NAME] |
Generate deploy/ callbacks locally |
git deploy setup -r REMOTE [--force] |
Create remote repo + install hook |
git deploy hooks -r REMOTE [--force] |
Refresh remote hook only |
git deploy log -r REMOTE [-l N] [-t] |
Tail deploy log (-t to follow) |
git deploy rerun -r REMOTE |
Re-run after_push on server |
git deploy restart -r REMOTE |
Run deploy/restart on server |
git deploy rollback -r REMOTE |
Reset to previous revision + callback |
git deploy upload -r REMOTE <files…> |
SCP local → server app dir |
git deploy download -r REMOTE <paths…> |
SCP server app dir → local |
Remote URL formats
| Remote | Deploy path |
|---|---|
user@host:/var/www/app |
/var/www/app (absolute) |
user@host:~/apps/app |
~/apps/app (home-relative) |
user@host:apps/app |
$HOME/apps/app (relative to remote $HOME) |
ssh://user@host:2222/path |
/path on port 2222 |
GitHub remotes are rejected — you cannot deploy to github.com.
Restart recipes
Match deploy/restart to your app server:
Passenger (default template):
touch tmp/restart.txt
Unicorn:
kill -USR2 $(cat tmp/pids/unicorn.pid)
Puma — use --template rails-puma, or:
bundle exec pumactl -P tmp/pids/puma.pid restart
PHP-FPM — use --template php-composer, or:
sudo systemctl reload php-fpm
Multiple environments
Use separate git remotes pointing at separate directories on the same (or different) host:
git remote add staging user@server:~/apps/myapp-staging
git remote add production user@server:~/apps/myapp-production
git deploy setup -r staging
git deploy setup -r production
git push staging develop
git push production main
Same deploy/ scripts usually work for both; set RAILS_ENV or equivalent in server environment or in the scripts.
Migrating from mislav/git-deploy
gem uninstall git-deploy(optional)gem install git-deploy-nggit deploy hooks -r productionon each host
Existing deploy/ scripts in your apps do not need to change. After upgrading, refresh hooks on each host to pick up improvements.
v0.9.0 compatibility changes: Minor CLI changes (notably -r required on all remote commands). Full list: CONTRIBUTING.md § Backwards compatibility, ROADMAP.md § v0.9.0.
Which git-deploy?
| Project | Model | Use when |
|---|---|---|
| git-deploy-ng (this repo) | Push-based: git push production main |
Heroku-style simplicity, modern Ruby |
| mislav/git-deploy | Original gem (archived ~0.7.0) | Legacy reference |
| git-deploy/git-deploy | Pull-based: git deploy start/sync/finish on a deploy host |
Locking, deploy tags, multi-server sync from a staging machine |
Troubleshooting
bundle or ruby not found on push (but git deploy rerun works)
git push runs hooks in a non-interactive shell that may not load .bashrc. This is usually a server environment issue:
- Initialize rbenv/rvm/nvm in
~/.profileor~/.bash_profile, not only.bashrc. - Or add
deploy/envon the server with PATH exports (sourced by the hook when present).
SSH key authentication
Set up key auth with ssh-copy-id before running setup. Password auth is not supported.
unsupported key type ssh-ed25519
gem install ed25519 bcrypt_pbkdf
git-deploy-ng prints this hint automatically when the gems are missing.
Setup refuses to overwrite hooks
Use --force when re-running setup or hooks on an existing deployment:
git deploy setup -r production --force
Development
git clone https://github.com/npfedwards/git-deploy.git
cd git-deploy
bundle install
bundle exec rspec
CI runs on Ubuntu and macOS against Ruby 2.7–4.0. Releases publish to RubyGems when a v* tag is pushed — see CONTRIBUTING.md.
License
MIT — see LICENSE. Originally by Mislav Marohnić; maintained by Nathan Edwards.