Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I automagically make a checkout upon push?

Tags:

git

githooks

Consider the following situation:

I have a git repository foo.git that contains code of a javascript project. In this repository there is a branch production that contains the state of the code as served by a web-server which fetches the code from /var/www/foo. This repository is the master repository for the project. Everybody pushes and pulls from/to it.

Is it possible to have /var/www/foo updated to a checkout of production whenever someobody pushes to that particular branch? You may assume that the git daemon (or the user git which is the user all people log in to to connect via SSH) is entitled to write to said directory.

like image 619
fuz Avatar asked Nov 28 '25 05:11

fuz


2 Answers

You have to create a bare repository on the server with git init --bare. Then use a post-receive hook to trigger your deploy. How you deploy is up to you.

My Deployment Strategy

I usually place a deploy director, somewhere logical. Then each checkout, I unpack the latest branch to deploy/COMMIT_ID where COMMIT_ID is the hash of the latest push. Once the checkout is complete, you can re-point a symlink to the latest deployment directory.

My usual directory structure:

deploy.git/
deploy/
    a7922231/
    b2f0a2af/
    latest -> b2f0a2af 

Unpacking the Update

Rather than use a git-checkout, I usually use git-archive to unpack a branch into a directory.

# Assuming current directory is deploy.git
HEAD=`cat refs/heads/master`
mkdir -p ../deploy/${HEAD}
git archive master | tar -x -C ../deploy/${HEAD}

Your web-server can point to deploy/latest, updates will be more-or-less atomic.

I use this often in production, and has a few benefits over unpacking over the same directory.

  1. rollbacks are easy
  2. you can do post-unpack procedures, like compile or install dependencies without interrupting the current deployment

Tips

  1. each update, append to a deploy log that says when updates occurred, and what their hash ids are. This makes rollbacks much easier.
like image 177
Jacob Groundwater Avatar answered Nov 30 '25 18:11

Jacob Groundwater


You have to create a file called post-receive in your /git/foo.git/hooks directory (based on my comment above). Something like this (with some debug log):

#!/bin/sh

echo 'Hook called'
pullneeded=false

while read oldrev newrev refname
do
    echo "OLDREV $oldrev NEWREV $newrev REFNAME $refname"
    if [ "$refname" == "refs/heads/production" ]; then
        echo 'Pull needed'
        pullneeded=true
    fi
done

if [ $pullneeded ]; then
    echo 'Pull'
    cd /var/www/foo
    git --git-dir=/var/www/foo/.git pull
fi

echo 'Hook done'

You have to set up your git repository at /var/www/foo to track the production branch of your other repository. If it's called origin there then it is:

git branch --set-upstream production origin/production

And of course the production branch has to be checked out in your /var/www/foo repository.

UPDATED

Maybe a post-update hook is more appropriate (sample is from here https://stackoverflow.com/a/6597728/299788):

#!/bin/bash    

case " $* " in
*' refs/heads/production '*)
    cd /var/www/foo
    git --git-dir=/var/www/foo/.git pull
    ;;
esac
like image 27
tewe Avatar answered Nov 30 '25 17:11

tewe