2

I'm implementing this approach to send updates to my website:

created bare repository to push to

$ mkdir website.git && cd website.git
$ git init --bare

And added the following hook:

$ mkdir /var/www/example.com
$ cat > hooks/post-receive
#!/bin/sh
GIT_WORK_TREE=/var/www/example.com git checkout -f
$ chmod +x hooks/post-receive

when I push to website.git from local repository, the update works fine. But no files are added into /var/www/example.com. How can I investigate what could be wrong here? Any kind of log or something?

EDIT ----------------------

The problem is fixed if I push to master branch on repoRemote, not demo. Why is so?

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488

6 Answers6

3

Edit, Dec 2016: people are still finding this old answer, and now, 3 years later, I truly understand what the real issue is. The problem occurs when you use a post-receive hook to deploy multiple different branches. If you only ever deploy one branch from a bare repository, you will have fewer problems. Git keeps evolving and the "best" solution for automatic deployment of several branches may vary depending on which Git version you have. See also Git post-receive deployment stops working at random points.

(Original answer below line.)


I've found that git checkout -f always needs a branch name; allowing it to use HEAD in bare repositories is not very predictable.

You may also run into issues with the index (git will write one in the bare repo, but it gets confused at times). It works best to git checkout -f deployment-branch into a new, fresh, empty directory. (It should work to set an index file per deployment-branch, I've just never gotten around to experimenting with this.)

If your bare repo will be fairly active on other branches than the one(s) used for deployment, it's a good idea to wrap the code with fancier shell-scripting that checks whether the deployment branch in question has actually been changed. That is, if someone updates web-devel, there's no point re-re-re-deploying deployment-branch, which they did not update this time.

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • Thanks, I've edited my question with solution I've found. But I don't understand why it's so. Maybe this explains it `git checkout -f always needs a branch name`? No `demo` branch can be created on bare repo and only `master` branch exists? – Max Koretskyi Nov 12 '13 at 13:12
  • 1
    If you, on your own personal repo, run `git checkout` without a branch name, what does it check out, and why? (That's meant as an exercise: you're supposed to figure out how `checkout` knows what to check out.) What branch do you expect git to check out into `/var/www/example.com`, and how do you expect it to know which branch to check out? – torek Nov 12 '13 at 18:40
  • You tell it what to checkout by specifying a branch name. If I don't specify it, then _the command degenerates to "check out the current branch", which is a glorified no-op with a rather expensive side-effects_. The current branch is what HEAD points at. In my case its `master` branch I guess. Now I see you point and why it's happening. OK, but doing this - `git checkout -f demo` gives this error `git branch fatal: This operation must be run in a work tree` even thought the demo branch exists `git branch` shows `demo`, but HEAD doesn't point to it. – Max Koretskyi Nov 13 '13 at 06:49
  • 1
    More precisely, it uses `HEAD`, which in a bare rep ... well: Normally `HEAD` gets updated to match your working directory as you work, but you don't actually *work* in a bare repo! There's a `HEAD` in a bare repo anyway, just because git always has to have one [if you remove it and run a git command, git says "I can't find a git directory here"], but it's rarely what you want it to be. Anyway, `git checkout -f demo` should work if `GIT_WORK_TREE` is set or if you use the `--work-tree=` argument. – torek Nov 13 '13 at 06:56
  • Thank you very much! `git checkout -f deployment-branch` worked as you said, it failed the first time since I had incorrect path of `GIT_WORK_TREE`, so it probably didn't know where the worktree was. – Max Koretskyi Nov 13 '13 at 07:29
1

Another possible cause for post-receive hook trouble is identified and fixed in Git 2.13 (Q2 2017): if the GIT_WORK_TREE is set to an invalid path.

See commit ce83ead, commit aac3eaa (08 Mar 2017) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit ba37c92, 13 Mar 2017)

Example (which would crash with Git 2.12 only)

GIT_WORK_TREE=/.invalid/work/tree &&
export GIT_WORK_TREE &&
git rev-parse
# dies with error code 128

The bug was introduced in Git 2.12.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
1

From comments above about reliability of targeting specific branches - I found this gist which targets the master branch from post-receive hook.

#!/bin/bash 
set -eu

TARGET="/deployment-location-here"
GIT_DIR="/trigger-location-here"
BRANCH="master"

while read oldrev newrev ref
do
        # only checking out the master (or whatever branch you would like to deploy)
        if [[ $ref = refs/heads/"$BRANCH" ]];
        then
                echo "Ref $ref received. Deploying ${BRANCH} branch to production..."
                git --work-tree="$TARGET" --git-dir="$GIT_DIR" checkout -f
        else
                echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."
        fi
done
johndpope
  • 5,035
  • 2
  • 41
  • 43
0
cd .git/hooks
mv post-receive post-receive-inner

now create a new post-receive:

#!/bin/bash
set -x
./post-receive-inner "$@" 1>/tmp/git.log 2>&1 

Make this executable and try again, the results should end up in /tmp/git.log

Oliver Matthews
  • 7,497
  • 3
  • 33
  • 36
  • I created new folder `hooks/post-receive-inner` and moved `post-receive` hook into it. Is that what I needed to do? Because the log currently states the following: `hooks/post-receive: line3: ./post-receive-inner: No such file or directory` – Max Koretskyi Nov 12 '13 at 09:25
  • this is what I did the first time :). The same message. Can you please specify the Linux commands I need to execute to eliminate my possible mistake? – Max Koretskyi Nov 12 '13 at 10:06
  • `./post-receive-inner` will fail because `.` is the bare repo directory, not the `hooks/` directory. `./hooks/post-receive-inner` would work. (But the `-x` setting won't carry over; for debug tracing you might want `sh -x hooks/post-receive-inner`.) – torek Nov 12 '13 at 12:12
0

I do this on my sites:

#!/bin/sh
unset $(git rev-parse --local-env-vars)
cd /var/www/example.com
git pull
JBarberU
  • 999
  • 8
  • 16
0

Make the script executable:

chmod +x .git/hooks/post-receive
Claudio
  • 10,614
  • 4
  • 31
  • 71
  • He did the `chmod` in the commands shown above (it's a `--bare` repo, so the file is named `hooks/post-receive`, without the `.git/` part). – torek Nov 12 '13 at 12:27