Is it possible to deploy a website using git push
? I have a hunch it has something to do with using git hooks to perform a git reset --hard
on the server side, but how would I go about accomplishing this?
This question is related to
git
deployment
webserver
githooks
Sounds like you should have two copies on your server. A bare copy, that you can push/pull from, which your would push your changes when you're done, and then you would clone this into you web directory and set up a cronjob to update git pull from your web directory every day or so.
In our scenario we're storing the code on github/bitbucket and want to deploy to live servers. In this case the following combination works for us (that is a remix of the highly upvoted answers here):
.git
directory to your web servergit remote add live ssh://user@host:port/folder
git config receive.denyCurrentBranch ignore
On remote: nano .git/hooks/post-receive
and add this content:
#!/bin/sh
GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f
On remote: chmod +x .git/hooks/post-receive
git push live
If your .git
folder is within document root make sure you hide it from the outside by adding to .htaccess
(source):
RedirectMatch 404 /\..*$
My take on Christians solution.
git archive --prefix=deploy/ master | tar -x -C $TMPDIR | rsync $TMPDIR/deploy/ --copy-links -av [email protected]:/home/user/my_app && rm -rf $TMPDIR/deploy
dont install git on a server or copy the .git folder there. to update a server from a git clone you can use following command:
git ls-files -z | rsync --files-from - --copy-links -av0 . [email protected]:/var/www/project
you might have to delete files which got removed from the project.
this copies all the checked in files. rsync uses ssh which is installed on a server anyways.
the less software you have installed on a server the more secure he is and the easier it is to manage it's configuration and document it. there is also no need to keep a complete git clone on the server. it only makes it more complex to secure everything properly.
The way I do it is I have a bare Git repository on my deployment server where I push changes. Then I log in to the deployment server, change to the actual web server docs directory, and do a git pull. I don't use any hooks to try to do this automatically, that seems like more trouble than it's worth.
You could conceivably set up a git hook that when say a commit is made to say the "stable" branch it will pull the changes and apply them to the PHP site. The big downside is you won't have much control if something goes wrong and it will add time to your testing - but you can get an idea of how much work will be involved when you merge say your trunk branch into the stable branch to know how many conflicts you may run into. It will be important to keep an eye on any files that are site specific (eg. configuration files) unless you solely intend to only run the one site.
Alternatively have you looked into pushing the change to the site instead?
For information on git hooks see the githooks documentation.
I am using the following solution by toroid.org, which has a simpler hook script.
on the server:
$ mkdir website.git && cd website.git
$ git init --bare
Initialized empty Git repository in /home/ams/website.git/
and install the hook on the server:
$ mkdir /var/www/www.example.org
$ cat > hooks/post-receive
#!/bin/sh
GIT_WORK_TREE=/var/www/www.example.org git checkout -f
GIT_WORK_TREE=/var/www/www git clean -f -d # clean directory from removed files
$ chmod +x hooks/post-receive
on your client:
$ mkdir website && cd website
$ git init
Initialized empty Git repository in /home/ams/website/.git/
$ echo 'Hello, world!' > index.html
$ git add index.html
$ git commit -q -m "The humble beginnings of my web site."
$ git remote add web ssh://server.example.org/home/ams/website.git
$ git push web +master:refs/heads/master
then to publish, just type
$ git push web
There is a full description on the website: http://toroid.org/ams/git-website-howto
We use capistrano for managing deploy. We build capistrano to deploy on a staging server, and then running a rsync with all of ours server.
cap deploy
cap deploy:start_rsync (when the staging is ok)
With capistrano, we can made easy rollback in case of bug
cap deploy:rollback
cap deploy:start_rsync
Update: I'm now using Lloyd Moore solution with the key agent ssh -A ...
. Pushing to a main repo and then pulling from it in parallel from all your machines is a bit faster and requires less setup on those machines.
Not seeing this solution here. just push via ssh if git is installed on the server.
You'll need the following entry in your local .git/config
[remote "amazon"]
url = amazon:/path/to/project.git
fetch = +refs/heads/*:refs/remotes/amazon/*
But hey, whats that with amazon:
? In your local ~/.ssh/config you'll need to add the following entry:
Host amazon
Hostname <YOUR_IP>
User <USER>
IdentityFile ~/.ssh/amazon-private-key
now you can call
git push amazon master
ssh <USER>@<YOUR_IP> 'cd /path/to/project && git pull'
(BTW: /path/to/project.git is different to the actual working directory /path/to/project)
You could conceivably set up a git hook that when say a commit is made to say the "stable" branch it will pull the changes and apply them to the PHP site. The big downside is you won't have much control if something goes wrong and it will add time to your testing - but you can get an idea of how much work will be involved when you merge say your trunk branch into the stable branch to know how many conflicts you may run into. It will be important to keep an eye on any files that are site specific (eg. configuration files) unless you solely intend to only run the one site.
Alternatively have you looked into pushing the change to the site instead?
For information on git hooks see the githooks documentation.
Using the post-update file below:
On your local copy, modify your .git/config file and add your web server as a remote:
[remote "production"]
url = username@webserver:/path/to/htdocs/.git
On the server, replace .git/hooks/post-update with file below
Add execute access to the file (again, on the server):
chmod +x .git/hooks/post-update
Now, just locally push to your web server and it should automatically update the working copy:
git push production
#!/bin/sh
#
# This hook does two things:
#
# 1. update the "info" files that allow the list of references to be
# queries over dumb transports such as http
#
# 2. if this repository looks like it is a non-bare repository, and
# the checked-out branch is pushed to, then update the working copy.
# This makes "push" function somewhat similarly to darcs and bzr.
#
# To enable this hook, make this file executable by "chmod +x post-update".
git-update-server-info
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
update_wc() {
ref=$1
echo "Push to checked out branch $ref" >&2
if [ ! -f $GIT_DIR/logs/HEAD ]
then
echo "E:push to non-bare repository requires a HEAD reflog" >&2
exit 1
fi
if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)
then
wc_dirty=0
else
echo "W:unstaged changes found in working copy" >&2
wc_dirty=1
desc="working copy"
fi
if git diff-index --cached HEAD@{1} >/dev/null
then
index_dirty=0
else
echo "W:uncommitted, staged changes found" >&2
index_dirty=1
if [ -n "$desc" ]
then
desc="$desc and index"
else
desc="index"
fi
fi
if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
then
new=$(git rev-parse HEAD)
echo "W:stashing dirty $desc - see git-stash(1)" >&2
( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT
git-update-ref --no-deref HEAD HEAD@{1}
cd $GIT_WORK_TREE
git stash save "dirty $desc before update to $new";
git-symbolic-ref HEAD "$ref"
)
fi
# eye candy - show the WC updates :)
echo "Updating working copy" >&2
(cd $GIT_WORK_TREE
git-diff-index -R --name-status HEAD >&2
git-reset --hard HEAD)
}
if [ "$is_bare" = "false" ]
then
active_branch=`git-symbolic-ref HEAD`
export GIT_DIR=$(cd $GIT_DIR; pwd)
GIT_WORK_TREE=${GIT_WORK_TREE-..}
for ref
do
if [ "$ref" = "$active_branch" ]
then
update_wc $ref
fi
done
fi
I ended up creating my own rudimentary deployment tool which would automatically pull down new updates from the repo - https://github.com/jesalg/SlimJim - Basically it listens to the github post-receive-hook and uses a proxy to trigger an update script.
Giddyup are language-agnostic just-add-water git hooks to automate deployment via git push. It also allows you to have custom start/stop hooks for restarting web server, warming up cache etc.
https://github.com/mpalmer/giddyup
Check out examples.
Sounds like you should have two copies on your server. A bare copy, that you can push/pull from, which your would push your changes when you're done, and then you would clone this into you web directory and set up a cronjob to update git pull from your web directory every day or so.
As complementary answer I would like to offer an alternative. I'm using git-ftp and it works fine.
https://github.com/git-ftp/git-ftp
Easy to use, only type:
git ftp push
and git will automatically upload project files.
Regards
I use two solutions for post-receive hook:
DEPLOY SOLUTION 1
#!/bin/bash
# /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed)
# DEPLOY SOLUTION 1
export GIT_DIR=/git/repo-bare.git
export GIT_BRANCH1=master
export GIT_TARGET1=/var/www/html
export GIT_BRANCH2=dev
export GIT_TARGET2=/var/www/dev
echo "GIT DIR: $GIT_DIR/"
echo "GIT TARGET1: $GIT_TARGET1/"
echo "GIT BRANCH1: $GIT_BRANCH1/"
echo "GIT TARGET2: $GIT_TARGET2/"
echo "GIT BRANCH2: $GIT_BRANCH2/"
echo ""
cd $GIT_DIR/
while read oldrev newrev refname
do
branch=$(git rev-parse --abbrev-ref $refname)
BRANCH_REGEX='^${GIT_BRANCH1}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET1/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
git checkout -f $branch
fi
BRANCH_REGEX='^${GIT_BRANCH2}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET2/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
git checkout -f $branch
fi
done
DEPLOY SOLUTION 2
#!/bin/bash
# /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed)
# DEPLOY SOLUTION 2
export GIT_DIR=/git/repo-bare.git
export GIT_BRANCH1=master
export GIT_TARGET1=/var/www/html
export GIT_BRANCH2=dev
export GIT_TARGET2=/var/www/dev
export GIT_TEMP_DIR1=/tmp/deploy1
export GIT_TEMP_DIR2=/tmp/deploy2
echo "GIT DIR: $GIT_DIR/"
echo "GIT TARGET1: $GIT_TARGET1/"
echo "GIT BRANCH1: $GIT_BRANCH1/"
echo "GIT TARGET2: $GIT_TARGET2/"
echo "GIT BRANCH2: $GIT_BRANCH2/"
echo "GIT TEMP DIR1: $GIT_TEMP_DIR1/"
echo "GIT TEMP DIR2: $GIT_TEMP_DIR2/"
echo ""
cd $GIT_DIR/
while read oldrev newrev refname
do
branch=$(git rev-parse --abbrev-ref $refname)
BRANCH_REGEX='^${GIT_BRANCH1}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET1/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
# DEPLOY SOLUTION 2:
cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR1;
export GIT_WORK_TREE=$GIT_TEMP_DIR1/.
git checkout -f $branch
export GIT_WORK_TREE=$GIT_TARGET1/.
rsync $GIT_TEMP_DIR1/. -v -q --delete --delete-after -av $GIT_TARGET1/.
rm -rf $GIT_TEMP_DIR1
fi
BRANCH_REGEX='^${GIT_BRANCH2}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET2/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
# DEPLOY SOLUTION 2:
cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR2;
export GIT_WORK_TREE=$GIT_TEMP_DIR2/.
git checkout -f $branch
export GIT_WORK_TREE=$GIT_TARGET2/.
rsync $GIT_TEMP_DIR2/. -v -q --delete --delete-after -av $GIT_TARGET2/.
rm -rf $GIT_TEMP_DIR2
fi
done
Both solutions are based on earlier solutions available in this thread.
Note, the BRANCH_REGEX='^${GIT_BRANCH1}.$' filters for the branch names matching "master" or "dev*" string, and deploys the work tree, if the pushed branch matches. This makes possible to deploy a dev version and master version to different places.
DEPLOY SOLUTION 1 removes only files, which are part of the repo, and was removed by a commit. It is faster than Deployment Solution 2.
DEPLOY SOLUTION 2 has the advantage, that it will remove any new files from the production directory, which was added on server side, no matter if it was added to the repo or not. It will be always clean dupe of the repo. It is slower than Deployment Solution 1.
My take on Christians solution.
git archive --prefix=deploy/ master | tar -x -C $TMPDIR | rsync $TMPDIR/deploy/ --copy-links -av [email protected]:/home/user/my_app && rm -rf $TMPDIR/deploy
The way I do it is I have a bare Git repository on my deployment server where I push changes. Then I log in to the deployment server, change to the actual web server docs directory, and do a git pull. I don't use any hooks to try to do this automatically, that seems like more trouble than it's worth.
We use capistrano for managing deploy. We build capistrano to deploy on a staging server, and then running a rsync with all of ours server.
cap deploy
cap deploy:start_rsync (when the staging is ok)
With capistrano, we can made easy rollback in case of bug
cap deploy:rollback
cap deploy:start_rsync
In essence all you need to do are the following:
server = $1
branch = $2
git push $server $branch
ssh <username>@$server "cd /path/to/www; git pull"
I have those lines in my application as an executable called deploy
.
so when I want to do a deploy I type ./deploy myserver mybranch
.
You could conceivably set up a git hook that when say a commit is made to say the "stable" branch it will pull the changes and apply them to the PHP site. The big downside is you won't have much control if something goes wrong and it will add time to your testing - but you can get an idea of how much work will be involved when you merge say your trunk branch into the stable branch to know how many conflicts you may run into. It will be important to keep an eye on any files that are site specific (eg. configuration files) unless you solely intend to only run the one site.
Alternatively have you looked into pushing the change to the site instead?
For information on git hooks see the githooks documentation.
The way I do it is I have a bare Git repository on my deployment server where I push changes. Then I log in to the deployment server, change to the actual web server docs directory, and do a git pull. I don't use any hooks to try to do this automatically, that seems like more trouble than it's worth.
Update: I'm now using Lloyd Moore solution with the key agent ssh -A ...
. Pushing to a main repo and then pulling from it in parallel from all your machines is a bit faster and requires less setup on those machines.
Not seeing this solution here. just push via ssh if git is installed on the server.
You'll need the following entry in your local .git/config
[remote "amazon"]
url = amazon:/path/to/project.git
fetch = +refs/heads/*:refs/remotes/amazon/*
But hey, whats that with amazon:
? In your local ~/.ssh/config you'll need to add the following entry:
Host amazon
Hostname <YOUR_IP>
User <USER>
IdentityFile ~/.ssh/amazon-private-key
now you can call
git push amazon master
ssh <USER>@<YOUR_IP> 'cd /path/to/project && git pull'
(BTW: /path/to/project.git is different to the actual working directory /path/to/project)
In essence all you need to do are the following:
server = $1
branch = $2
git push $server $branch
ssh <username>@$server "cd /path/to/www; git pull"
I have those lines in my application as an executable called deploy
.
so when I want to do a deploy I type ./deploy myserver mybranch
.
The way I do it is I have a bare Git repository on my deployment server where I push changes. Then I log in to the deployment server, change to the actual web server docs directory, and do a git pull. I don't use any hooks to try to do this automatically, that seems like more trouble than it's worth.
git config --local receive.denyCurrentBranch updateInstead
Added in Git 2.3, this could be a good possibility: https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155
You set it on the server repository, and it also updates the working tree if it is clean.
There have been further improvements in 2.4 with the push-to-checkout
hook and handling of unborn branches.
Sample usage:
git init server
cd server
touch a
git add .
git commit -m 0
git config --local receive.denyCurrentBranch updateInstead
cd ..
git clone server local
cd local
touch b
git add .
git commit -m 1
git push origin master:master
cd ../server
ls
Output:
a
b
This does have the following shortcomings mentioned on the GitHub announcement:
But all of those points are out of the scope of Git and must be taken care of by external code. So in that sense, this, together with Git hooks, are the ultimate solution.
Sounds like you should have two copies on your server. A bare copy, that you can push/pull from, which your would push your changes when you're done, and then you would clone this into you web directory and set up a cronjob to update git pull from your web directory every day or so.
I ended up creating my own rudimentary deployment tool which would automatically pull down new updates from the repo - https://github.com/jesalg/SlimJim - Basically it listens to the github post-receive-hook and uses a proxy to trigger an update script.
git config --local receive.denyCurrentBranch updateInstead
Added in Git 2.3, this could be a good possibility: https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155
You set it on the server repository, and it also updates the working tree if it is clean.
There have been further improvements in 2.4 with the push-to-checkout
hook and handling of unborn branches.
Sample usage:
git init server
cd server
touch a
git add .
git commit -m 0
git config --local receive.denyCurrentBranch updateInstead
cd ..
git clone server local
cd local
touch b
git add .
git commit -m 1
git push origin master:master
cd ../server
ls
Output:
a
b
This does have the following shortcomings mentioned on the GitHub announcement:
But all of those points are out of the scope of Git and must be taken care of by external code. So in that sense, this, together with Git hooks, are the ultimate solution.
Sounds like you should have two copies on your server. A bare copy, that you can push/pull from, which your would push your changes when you're done, and then you would clone this into you web directory and set up a cronjob to update git pull from your web directory every day or so.
After many false starts and dead ends, I'm finally able to deploy website code with just "git push remote" thanks to this article.
The author's post-update script is only one line long and his solution doesn't require .htaccess configuration to hide the Git repo as some others do.
A couple of stumbling blocks if you're deploying this on an Amazon EC2 instance;
1) If you use sudo to create the bare destination repository, you have to change the owner of the repo to ec2-user or the push will fail. (Try "chown ec2-user:ec2-user repo.")
2) The push will fail if you don't pre-configure the location of your amazon-private-key.pem, either in /etc/ssh/ssh_config as an IdentityFile parameter or in ~/.ssh/config using the "[Host] - HostName - IdentityFile - User" layout described here...
...HOWEVER if Host is configured in ~/.ssh/config and different than HostName the Git push will fail. (That's probably a Git bug)
As complementary answer I would like to offer an alternative. I'm using git-ftp and it works fine.
https://github.com/git-ftp/git-ftp
Easy to use, only type:
git ftp push
and git will automatically upload project files.
Regards
Given an environment where you have multiple developers accessing the same repository the following guidelines may help.
Ensure that you have a unix group that all devs belong to and give ownership of the .git repository to that group.
In the .git/config of the server repository set sharedrepository = true. (This tells git to allow multiple users which is needed for commits and deployment.
set the umask of each user in their bashrc files to be the same - 002 is a good start
After many false starts and dead ends, I'm finally able to deploy website code with just "git push remote" thanks to this article.
The author's post-update script is only one line long and his solution doesn't require .htaccess configuration to hide the Git repo as some others do.
A couple of stumbling blocks if you're deploying this on an Amazon EC2 instance;
1) If you use sudo to create the bare destination repository, you have to change the owner of the repo to ec2-user or the push will fail. (Try "chown ec2-user:ec2-user repo.")
2) The push will fail if you don't pre-configure the location of your amazon-private-key.pem, either in /etc/ssh/ssh_config as an IdentityFile parameter or in ~/.ssh/config using the "[Host] - HostName - IdentityFile - User" layout described here...
...HOWEVER if Host is configured in ~/.ssh/config and different than HostName the Git push will fail. (That's probably a Git bug)
Given an environment where you have multiple developers accessing the same repository the following guidelines may help.
Ensure that you have a unix group that all devs belong to and give ownership of the .git repository to that group.
In the .git/config of the server repository set sharedrepository = true. (This tells git to allow multiple users which is needed for commits and deployment.
set the umask of each user in their bashrc files to be the same - 002 is a good start
dont install git on a server or copy the .git folder there. to update a server from a git clone you can use following command:
git ls-files -z | rsync --files-from - --copy-links -av0 . [email protected]:/var/www/project
you might have to delete files which got removed from the project.
this copies all the checked in files. rsync uses ssh which is installed on a server anyways.
the less software you have installed on a server the more secure he is and the easier it is to manage it's configuration and document it. there is also no need to keep a complete git clone on the server. it only makes it more complex to secure everything properly.
In our scenario we're storing the code on github/bitbucket and want to deploy to live servers. In this case the following combination works for us (that is a remix of the highly upvoted answers here):
.git
directory to your web servergit remote add live ssh://user@host:port/folder
git config receive.denyCurrentBranch ignore
On remote: nano .git/hooks/post-receive
and add this content:
#!/bin/sh
GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f
On remote: chmod +x .git/hooks/post-receive
git push live
If your .git
folder is within document root make sure you hide it from the outside by adding to .htaccess
(source):
RedirectMatch 404 /\..*$
Giddyup are language-agnostic just-add-water git hooks to automate deployment via git push. It also allows you to have custom start/stop hooks for restarting web server, warming up cache etc.
https://github.com/mpalmer/giddyup
Check out examples.
I am using the following solution by toroid.org, which has a simpler hook script.
on the server:
$ mkdir website.git && cd website.git
$ git init --bare
Initialized empty Git repository in /home/ams/website.git/
and install the hook on the server:
$ mkdir /var/www/www.example.org
$ cat > hooks/post-receive
#!/bin/sh
GIT_WORK_TREE=/var/www/www.example.org git checkout -f
GIT_WORK_TREE=/var/www/www git clean -f -d # clean directory from removed files
$ chmod +x hooks/post-receive
on your client:
$ mkdir website && cd website
$ git init
Initialized empty Git repository in /home/ams/website/.git/
$ echo 'Hello, world!' > index.html
$ git add index.html
$ git commit -q -m "The humble beginnings of my web site."
$ git remote add web ssh://server.example.org/home/ams/website.git
$ git push web +master:refs/heads/master
then to publish, just type
$ git push web
There is a full description on the website: http://toroid.org/ams/git-website-howto
You could conceivably set up a git hook that when say a commit is made to say the "stable" branch it will pull the changes and apply them to the PHP site. The big downside is you won't have much control if something goes wrong and it will add time to your testing - but you can get an idea of how much work will be involved when you merge say your trunk branch into the stable branch to know how many conflicts you may run into. It will be important to keep an eye on any files that are site specific (eg. configuration files) unless you solely intend to only run the one site.
Alternatively have you looked into pushing the change to the site instead?
For information on git hooks see the githooks documentation.
Using the post-update file below:
On your local copy, modify your .git/config file and add your web server as a remote:
[remote "production"]
url = username@webserver:/path/to/htdocs/.git
On the server, replace .git/hooks/post-update with file below
Add execute access to the file (again, on the server):
chmod +x .git/hooks/post-update
Now, just locally push to your web server and it should automatically update the working copy:
git push production
#!/bin/sh
#
# This hook does two things:
#
# 1. update the "info" files that allow the list of references to be
# queries over dumb transports such as http
#
# 2. if this repository looks like it is a non-bare repository, and
# the checked-out branch is pushed to, then update the working copy.
# This makes "push" function somewhat similarly to darcs and bzr.
#
# To enable this hook, make this file executable by "chmod +x post-update".
git-update-server-info
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
update_wc() {
ref=$1
echo "Push to checked out branch $ref" >&2
if [ ! -f $GIT_DIR/logs/HEAD ]
then
echo "E:push to non-bare repository requires a HEAD reflog" >&2
exit 1
fi
if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)
then
wc_dirty=0
else
echo "W:unstaged changes found in working copy" >&2
wc_dirty=1
desc="working copy"
fi
if git diff-index --cached HEAD@{1} >/dev/null
then
index_dirty=0
else
echo "W:uncommitted, staged changes found" >&2
index_dirty=1
if [ -n "$desc" ]
then
desc="$desc and index"
else
desc="index"
fi
fi
if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
then
new=$(git rev-parse HEAD)
echo "W:stashing dirty $desc - see git-stash(1)" >&2
( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT
git-update-ref --no-deref HEAD HEAD@{1}
cd $GIT_WORK_TREE
git stash save "dirty $desc before update to $new";
git-symbolic-ref HEAD "$ref"
)
fi
# eye candy - show the WC updates :)
echo "Updating working copy" >&2
(cd $GIT_WORK_TREE
git-diff-index -R --name-status HEAD >&2
git-reset --hard HEAD)
}
if [ "$is_bare" = "false" ]
then
active_branch=`git-symbolic-ref HEAD`
export GIT_DIR=$(cd $GIT_DIR; pwd)
GIT_WORK_TREE=${GIT_WORK_TREE-..}
for ref
do
if [ "$ref" = "$active_branch" ]
then
update_wc $ref
fi
done
fi
I use two solutions for post-receive hook:
DEPLOY SOLUTION 1
#!/bin/bash
# /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed)
# DEPLOY SOLUTION 1
export GIT_DIR=/git/repo-bare.git
export GIT_BRANCH1=master
export GIT_TARGET1=/var/www/html
export GIT_BRANCH2=dev
export GIT_TARGET2=/var/www/dev
echo "GIT DIR: $GIT_DIR/"
echo "GIT TARGET1: $GIT_TARGET1/"
echo "GIT BRANCH1: $GIT_BRANCH1/"
echo "GIT TARGET2: $GIT_TARGET2/"
echo "GIT BRANCH2: $GIT_BRANCH2/"
echo ""
cd $GIT_DIR/
while read oldrev newrev refname
do
branch=$(git rev-parse --abbrev-ref $refname)
BRANCH_REGEX='^${GIT_BRANCH1}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET1/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
git checkout -f $branch
fi
BRANCH_REGEX='^${GIT_BRANCH2}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET2/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
git checkout -f $branch
fi
done
DEPLOY SOLUTION 2
#!/bin/bash
# /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed)
# DEPLOY SOLUTION 2
export GIT_DIR=/git/repo-bare.git
export GIT_BRANCH1=master
export GIT_TARGET1=/var/www/html
export GIT_BRANCH2=dev
export GIT_TARGET2=/var/www/dev
export GIT_TEMP_DIR1=/tmp/deploy1
export GIT_TEMP_DIR2=/tmp/deploy2
echo "GIT DIR: $GIT_DIR/"
echo "GIT TARGET1: $GIT_TARGET1/"
echo "GIT BRANCH1: $GIT_BRANCH1/"
echo "GIT TARGET2: $GIT_TARGET2/"
echo "GIT BRANCH2: $GIT_BRANCH2/"
echo "GIT TEMP DIR1: $GIT_TEMP_DIR1/"
echo "GIT TEMP DIR2: $GIT_TEMP_DIR2/"
echo ""
cd $GIT_DIR/
while read oldrev newrev refname
do
branch=$(git rev-parse --abbrev-ref $refname)
BRANCH_REGEX='^${GIT_BRANCH1}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET1/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
# DEPLOY SOLUTION 2:
cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR1;
export GIT_WORK_TREE=$GIT_TEMP_DIR1/.
git checkout -f $branch
export GIT_WORK_TREE=$GIT_TARGET1/.
rsync $GIT_TEMP_DIR1/. -v -q --delete --delete-after -av $GIT_TARGET1/.
rm -rf $GIT_TEMP_DIR1
fi
BRANCH_REGEX='^${GIT_BRANCH2}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET2/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
# DEPLOY SOLUTION 2:
cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR2;
export GIT_WORK_TREE=$GIT_TEMP_DIR2/.
git checkout -f $branch
export GIT_WORK_TREE=$GIT_TARGET2/.
rsync $GIT_TEMP_DIR2/. -v -q --delete --delete-after -av $GIT_TARGET2/.
rm -rf $GIT_TEMP_DIR2
fi
done
Both solutions are based on earlier solutions available in this thread.
Note, the BRANCH_REGEX='^${GIT_BRANCH1}.$' filters for the branch names matching "master" or "dev*" string, and deploys the work tree, if the pushed branch matches. This makes possible to deploy a dev version and master version to different places.
DEPLOY SOLUTION 1 removes only files, which are part of the repo, and was removed by a commit. It is faster than Deployment Solution 2.
DEPLOY SOLUTION 2 has the advantage, that it will remove any new files from the production directory, which was added on server side, no matter if it was added to the repo or not. It will be always clean dupe of the repo. It is slower than Deployment Solution 1.
Source: Stackoverflow.com