Friday, May 25, 2012

Deploy a project using Git push


Is it possible to deploy a PHP 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?



Source: Tips4all

14 comments:

  1. I found this script on this site and it seems to work quite well.


    Copy over your .git directory to your web server
    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 this file (mirror in so)
    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

    ReplyDelete
  2. For all of those looking for the post-update file, here it goes:

    #!/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


    Alternatively, you may find it in Google's cache:

    http://webcache.googleusercontent.com/search?q=cache:yNTUFsYBYFMJ:utsl.gen.nz/git/post-update+http://utsl.gen.nz/git/post-update&cd=1&hl=en&ct=clnk&gl=ie

    ReplyDelete
  3. 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)

    ReplyDelete
  4. 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.

    ReplyDelete
  5. 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 . user@server.com:/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.

    ReplyDelete
  6. 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.

    ReplyDelete
  7. 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)

    ReplyDelete
  8. 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.

    ReplyDelete
  9. I've just released a project called Giddyup! designed to make deployment using "git push" as simple as it possibly can be. It's language- and framework-agnostic, and aims to be simple to install, and to make deployment as simple as possible. I think it'll suit your requirements quite well.

    ReplyDelete
  10. 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.

    ReplyDelete
  11. 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.

    ReplyDelete
  12. 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

    ReplyDelete
  13. I found this one and it works really great:

    http://toroid.org/ams/git-website-howto

    ReplyDelete
  14. 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.

    ReplyDelete