0

As a sole developer on a project, I'm trying to thrash out a simple development and deployment workflow with git, constrained by using a single server for staging and production.

The production path is /var/www/vhosts/site.com

The staging path is /var/www/vhosts/staging.site.com

I understand how to create a branch for staging and that it's best to have prime (live site code) and hub (clone codebase) repos on the server, and then create a local working clone from the hub. But how do I create a git repo in /var/www/vhosts/ that serves both production and staging? Do I need separate repos?

Community
  • 1
  • 1
Michael Millar
  • 1,364
  • 2
  • 24
  • 46

2 Answers2

1

From the article, you have one main, bare repository called 'hub'. The 'prime' repository and the repository on your computer are clones of 'hub'.

In your situation, you have two 'prime' repositories: one is your staging area ('prime-staging') and one is your production area ('prime-production').

Using a combination of the hooks described in the article and the one described here (that takes a certain action depending on which branch is pushed), your 'prime-staging' or 'prime-production' repositories will be updated.

The 'hub repository should have two branches: master (or staging) associated with your staging site and production associated with your production site. You would do all your work on master, and push these changes to 'hub', allowing the git hook to update the staging repository. You would look at these changes in the live environment, making any changes needed on master and pushing again to 'hub'. Once the staging site looks good, you would do:

git checkout production
git reset --hard master
git push origin production

Now, the git hook will see that the production branch has been updated and update your production site accordingly. (NB: assuming hub is just the nomenclature, it's standard to call your primary repository origin)

So the setup I imagine on the server is:

mkdir -p /path/to/site.git
cd /path/to/site.git                          #// hub
git init --bare
cd /var/www/vhosts
git clone /path/to/site.git site.com          #// prime-production
git clone /path/to/site.git staging.site.com  #// prime-staging

You place the hooks in site.git. When the staging branch is updated, change into /var/www/vhosts/staging.site.com and execute a git pull. And do the same when the production branch is updated for /var/www/vhosts/site.com.

Community
  • 1
  • 1
houtanb
  • 3,852
  • 20
  • 21
  • very clear, I'm still reading up on git, trying to be cautious. When I run `git init` then `git add .` in `var/www/vhosts`, there will be `site.com` and `staging.site.com` in top level of the one prime repo. What commands do I use to create the two prime repos (staging and production), as they are in the same folder? – Michael Millar Nov 04 '15 at 15:10
  • @kaska I updated the answer with an answer to your question in the comment because the markdown in the answer is better than that available in the comment. – houtanb Nov 04 '15 at 15:40
  • @kaska also note that ojrask's solution will work as well. It's the "gittier" way of doing things. I chose the solution above because it seemed to go well with the article in your original question. The solution you choose is up to you. – houtanb Nov 04 '15 at 15:42
  • I tried ojraks's solution and it would work if I was deploying into empty directories but this has existing code (a live site). When I run the git clone command above I get `fatal: destination path 'staging.site.com' already exists and is not an empty directory`. – Michael Millar Nov 05 '15 at 08:29
  • Well, of course. The setup I provided is to set this up from scratch. To get around this problem, in the part of the hook that chooses what to do when you push the `production` branch, you should just copy over the files you'll need to `staging.site.com`, leaving it as is (recall that currently the hook changes into `staging.site.com` and does a git pull). Of course, the cleanest solution is to make `staging.site.com` a git repository, which would mean that you'd have to switch it over from its current non-git form. – houtanb Nov 05 '15 at 09:15
1

You can use external work trees and change them "on the fly" for bare repos.

Setup the bare repo on your server and then create a post-receive hook for it to do the deployments.

#!/bin/bash
# post-receive
# deploy production and staging to vhost dirs

# Directory we are deploying to. Should be the directory where the repo's root .gitignore would exist in.
PRODDEST="/path/to/destination/of/production"
STAGDEST="/path/to/destination/of/staging"

while read oldrev newrev refname; do
    # Grab the name of the branch that was pushed.
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)

    if [ "master" = "$branch" ]; then
        echo "Master push, deploy production..."
        GIT_WORK_TREE=$PRODDEST git checkout -f master
        GIT_WORK_TREE=$PRODDEST git clean -fd

    elif [ "develop" = "$branch" ]; then
        echo "Develop push, deploy staging..."
        GIT_WORK_TREE=$STAGDEST git checkout -f develop
        GIT_WORK_TREE=$STAGDEST git clean -fd
    fi
done

This has been adapted from a single-branch deployment script I use. I did not test it so it may need to be tweaked.

Essentially the bare repo runs the hook and checks if the push was a master push (and deploys production) or a develop push (and deploys staging).

You could also expand this hook to call build tools after the changes have been checked out to compile assets and what not. I usually remove all development packages, sources and build tools after everything is done.

EDIT: this does not work if you need to push a single branch to multiple deploy locations. Not sure what parameters can be sent with pushes, or if remote names could be used somehow.

ojrask
  • 2,799
  • 1
  • 23
  • 23
  • I think I've nearly got this working with your script. To test it out I created two new folders in `/var/www/vhosts`. I am able to push my changes to either of these dummy production + staging folders. But then when I switch the STAGDEST to the genuine folder, which has existing code there, I get lots of `remote: warning: failed to remove ...` errors when trying to push – Michael Millar Nov 04 '15 at 20:33
  • which I suppose is what you're getting at in your last sentences? is there a way I can flush it out or something (git clean) and allow me to deploy afresh? – Michael Millar Nov 04 '15 at 20:56
  • Oh bummer, I forgot to change a `master` to `develop` in the script example. The develop part should checkout develop, not master. If you have existing files in the deploy destination the script may not work properly, so a cleanup may be needed. – ojrask Nov 04 '15 at 21:11
  • by cleanup do you mean removing the files from production? Because it's a live site so it can't have downtime. In that case I assume I'd need to find an alternative method to set git up for this kind of deployment – Michael Millar Nov 04 '15 at 21:38
  • Yeah, removing all existing file from production. In this case I would suggest copying over the contents of production elsewhere and point the virtual host document root there or symlink the old directory to the new one. This way you could at least test out the deployment system and symlink the new deploy to the vhost location while keeping the current working production system readily available in case something goes awry. – ojrask Nov 05 '15 at 10:20