问题
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.
回答1:
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.
- rollbacks are easy
- you can do post-unpack procedures, like compile or install dependencies without interrupting the current deployment
Tips
- each update, append to a deploy log that says when updates occurred, and what their hash ids are. This makes rollbacks much easier.
回答2:
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
回答3:
You can check out a git repository foo.git
into a directory dir
with the following commands:
git archive | tar x dir
来源:https://stackoverflow.com/questions/14667128/how-can-i-automagically-make-a-checkout-upon-push