How can I automagically make a checkout upon push?

人走茶凉 提交于 2019-12-10 10:22:29

问题


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.

  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.



回答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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!