Question

I have a central, bare, git repository which all of our developers push to. This is our origin. I use origin to push to a separate, non-bare, repository and overwrite all changes. This is intended to be a demonstration area, so we can immediately see changes when somebody pushes to a specific branch.

Origin will push to the demo repository, but the working files are not changed. I have a post-receive hook on origin that calls:

git push -f ssh://git@<host>/<path> <branch name>

Then my post-receive hook on the demo repo calls:

git fetch origin <branch name>
git reset --hard FETCH_HEAD

If I call those commands on the demo box, my working copy updates fine. But calling them from the post-receive (on the demo repo) leaves changes which need to be manually committed. I want to skip the step where I manually update the working copy.

I realize, through some google-fu and stackoverflow searching, that it's generally bad practice to push to a non-bare repository. I understand the risks, but I'd like this to work, since we use a bare repository for our origin.

Does git do some kind of extra check to prevent the working copy from being updated by the post-receive? Is there any workaround?

Was it helpful?

Solution

There is a way to do this right, which will solve your problem too:

  1. Separate the working site to a bare git repo and to a working dir, let's call them /repos/demo.git and /sites/demo, respectively

  2. Push to your demo repo as usual, that part is fine

  3. In the post-receive hook of the demo repo, update the working dir with:

    git --work-tree /sites/demo reset --hard branchname
    

    where branchname is the name of the branch that was received (that you pushed)

This way you will not violate good practices: your demo repo is bare, so it's perfectly normal to push to it. There is no git fetch step, it's unnecessary, since the demo repo has just received the commits, there's nothing to fetch.

The --work-tree is of course the main trick here. It makes git commands manipulate a directory at a different place, and you can use this with bare repositories too. Inside the hook, I think the directory of the bare git repo is correctly set. If not, you can force it with the --git-dir option:

git --git-dir /repos/demo.git --work-tree /sites/demo reset --hard branchname
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top