1

I want to setup git for a somewhat unusual use case.

I have a repository server ('repo') and I have a develop server ('develop') I want to deploy to. On the repo server I have a bare repo ('origin') which I push my changes to from my local clone.

When I push a branch called 'development' to the repo server, I have a post-receive hook there that pushes the branch to the development server:

#!/bin/bash

# post-receive on repo server

while read oldrev newrev ref
  do
  branch=`echo $ref | cut -d/ -f3`

  if [ "development" == "$branch" ]; then
    git push develop development
    echo 'Changes pushed to development server.'
  fi
done

exit 0;

On the development server I have a post-receive hook that reads

#!/bin/bash
GIT_WORK_TREE=/srv/www/htdocs/develop git checkout -f

On the develop server it might be the case that someone made changes directly in the the working tree which resides in /srv/www/htdocs/develop without using git (yeah, I know, don't ask…).

Now: What is the best way to prevent the checkout on the develop server which would destroy the non-gitters modifications?

At the moment I simulate this case using a pre-receive hook on the repo server which echoes a message and exits 1.

It would be great if I do

$ git push origin development

and git would answer like so:

Counting objects: 11, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), 706 bytes, done.
Total 9 (delta 3), reused 0 (delta 0)
remote: Unclean working directory on development server. Please fix that first.
To git@repo:development
 ! [remote rejected] development -> development (pre-receive hook declined)
error: failed to push some refs to git@repo:development'
xlttj
  • 1,068
  • 2
  • 9
  • 15
  • IMHO this is not an unusual use case, but a very common one. In fact, I think it's the obvious way to deploy a web site. I actually had this working at my old job and am trying to re-find the answer I had then... It would even give a list of files that had been changed. – rjmunro Feb 02 '12 at 18:13

1 Answers1

0

I am using the "offical" post-update hook mentioned here: https://stackoverflow.com/a/3838796/3408 to prevent update the remote checkout after push.

I took some code from that to initialise the environment, and made a script to run git diff --exit-code --stat in a pre-receive hook. The --exit-code means that if there are differences, the push will be refused.

#!/bin/bash

is_bare=$(git config --get --bool core.bare)

if [ -z "$is_bare" ]
then
    # for compatibility's sake, guess
    git_dir_full=$(cd $GIT_DIR; pwd)
    case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac
fi

if [ "$is_bare" = "false" ]
then
    active_branch=`git symbolic-ref HEAD`
    export GIT_DIR=$(cd $GIT_DIR; pwd)
    GIT_WORK_TREE=${GIT_WORK_TREE-..}
    while read oldrev newrev ref
    do
        if [ "$ref" = "$active_branch" ]
        then
            (cd $GIT_WORK_TREE; git diff --exit-code --stat >&2)
        fi
    done
fi

I've just got this working, it's only basically tested. Others may be able to comment on if this can be simplified or improved.

Community
  • 1
  • 1
rjmunro
  • 24,825
  • 18
  • 102
  • 130