Material for my Git Workshop.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Clermont'ech Workshop Git

The aim of this (very short) workshop is to learn various ways to deploy with Git. We are going to cover:

1. Deploy Using Git Push/Hook

We need two separate folders to simulate two different servers:

mkdir {local,remote}-server

In the first folder, let's create an app:

cd local-server
mkdir app
cd !$
git init
echo "Hello, World" > index.html
git add index.html
git commit -m "Initial commit"

Let's add a new remote that points to the production server:

git remote add production /absolute/path/to/remote-server/www

Now, we are going to configure the remote server.

cd ../../remote-server
mkdir www
cd !$
git init

Let's edit the .git/config file, adding the content below to allow push on the current branch:

    denyCurrentBranch = false

Now, let's create a post-receive hook with the following content:

#!/usr/bin/env bash

set -eo pipefail

readonly LOGFILE="/tmp/deploy-app.log"

function notify()
    echo "Hi! I am your Git deployer, and I am deploying branch \"$1\" right now :-)"

function log()
    [[ -f "$LOGFILE" ]] || touch "$LOGFILE"

    echo "$2 ($3) successfully deploy branch: $1" >> "$LOGFILE"

function main()
    # STDIN: oldrev newrev ref
    while read _ newrev ref
        local branch=$(echo "$ref" | cut -d/ -f3)

        # Abort if there's no update, or in case the branch is deleted
        if [[ -z "${newrev//0}" ]] ; then

        if [[ "$branch" ]] ; then
            notify "$branch"

            cd ..
            unset GIT_DIR GIT_WORK_TREE

            git checkout "$branch" &> /dev/null
            git reset --hard &> /dev/null

            local author_name=$(git log -1 --format=format:%an HEAD)
            local author_email=$(git log -1 --format=format:%ae HEAD)

            log "$branch" "$author_name" "$author_email"

main "$@"

Make it executable:

chmod +x .git/hooks/post-receive

This hook is all you need to perform steps at "deploy time".

Let's test it!

cd ../../local-server/app
git push production master


ls -l /absolute/path/to/remote-server/www
tail /tmp/deploy-app.log

Note: git-deploy (almost) does the same thing, but probably better.

More on this hook

One may want to send emails to the person who just deployed. That is why author_name and author_email are retrieved.

Let's try to change the author's email:

echo "<h1>Hello, World</h1>" > index.html
git add !$ git commit -m "Surround title with html tags"
git push production master

Deploying to another branch

We can deploy another branch:

git checkout -b feat-content
echo "<p>content</p>" >> index.html
git add !$
git commit -m "add content"
git push production feat-content


tail /tmp/deploy-app.log
cat /absolute/path/to/remote-server/www/index.html

2. Deploy With Heroku

We are going to deploy a Node.JS application, that is a Chat Example.


Heroku Toolbelt

Install the Heroku Toolbelt.


heroku login
heroku git:clone -a <heroku-app-id>
cd !$

Make changes, then deploy:

git add .
git commit -m "Make it better"
git push heroku master

3. Deploy With Dokku

Dokku, Docker powered mini-Heroku in around 100 lines of Bash.

Clone the Chat Example:

git clone git://

Configure SSH to use the provided keys:

  User dokku
  PreferredAuthentications publickey
  IdentityFile    ~/.ssh/clermontech_git_rsa

Now, let's add a new remote pointing to the Dokku server:

git remote add deploy


git push deploy master


4. Capistrano

Capistrano, a remote server automation and deployment tool written in Ruby.

Install it:

gem install capistrano

Then, capify your application:

cd chat-example
cap install

Edit config/deploy.rb:

-set :application, 'my_app_name'
-set :repo_url, ''
+set :application, 'chat-example'
+set :repo_url, 'file:///absolute/path/to/chat-example/.git'

-# set :deploy_to, '/var/www/my_app'
+set :deploy_to, "/absolute/path/to/remote-server/capwww"

Edit config/deploy/production.rb:

-role :app, %w{}
-role :web, %w{}
-role :db,  %w{}
+role :app, %w{username@localhost}
+role :web, %w{username@localhost}

-server '', user: 'deploy', roles: %w{web app}, my_property: :my_value
+server 'localhost', user: 'username', roles: %w{web app}

-#  set :ssh_options, {
-#    keys: %w(/home/rlisowski/.ssh/id_rsa),
-#    forward_agent: false,
-#    auth_methods: %w(password)
-#  }
+set :ssh_options, {
+  keys: %w(/absolute/path/to/your/.ssh/identity-file),
+  forward_agent: false,
+  auth_methods: %w(publickey)

Check your settings:

cap production deploy:check


cap production deploy


ls -l /path/to/remote-server/capwww


Need help with all these Capistrano tasks:

cap -T

Manually Start The Application

Manually start the application:

cd /path/to/remote-server/capwww/current
npm start

Doh! Bad luck, it does not work.

Let's create a Capistrano task to install NPM dependencies:

namespace :nodejs do

  desc "Install modules non-globally"
  task :npm_install do
    on roles(:app) do
      execute "cd #{current_path} && /usr/bin/env npm install"


Tell Capistrano to execute it after each deploy:

namespace :deploy do
  # ...

  before :restart, 'nodejs:npm_install'

Deploy again.

Automatically Start The Application

Let's add a task to automatically start the application:

namespace :nodejs do
  # ...

  desc 'Start app'
  task :start do
    on roles(:app) do
      execute "cd #{current_path} && /usr/bin/env node index.js &"


Start your application:

cap production nodejs:start