Blog
Some of my thought on technology and programming.
Deploying via FTP is fraught with issues. When you delete a file locally you must ensure that the delete is replicated to the remote server and how can you be sure that all new files are replicated to the server? Dreamweaver does a good job of handling all of this for you but there are better ways…
The better way (in my opinion) is via your existing version control system (you are using version control, right?) like Git, Mercurial, Bzr or (God forbid) Subversion.
I shall assume that you are using and are fairly familiar with Git. So, lets get started.
We are going to create a deployment script which will:
- Fetch your repository from a remote repository (BitBucket)
- Checkout your chosen branch
- Process and checkout any submodules you may have
- Copy all of this content into your web server folder (you will be able to exclude certain content from the copy process)
Our architecture will be as follows:
- Work locally, using WAMP or MAMP (or whatever) with Git for Version Control (I use SourceTree)
- Push changes to your remote repository (I will be using BitBucket because of it's free private repositories)
- Pull changes from the remote repository and drop them into your Apache document root
Solution
Set up SSH
First, we will need to give the remote respository server a Deployment Key. To do this, we will need to generate an SSH key pair so that our server can talk to our code repository.
So lets run the following command:
ssh-keygen -t rsa
Now, we need to copy the public key so that we can give it to BitBucket. You can access this by entering the following command and copying the output to the clipboard:
cat ~/.ssh/id_rsa.pub
Paste the public key into the deployment keys section of your repository's settings (refer to either Github or BitBucket's help to see how to do this).
Next, create a config file in your ~/.ssh
folder. This will allow ssh to associate the correct private ssh key with our server:
Host bitbucket.org User git IdentityFile ~/.ssh/id_rsa
Set up Git
Create a new folder to hold the git repo:
mkdir [folder_name]
Now, we need to create a new git repository on the server:
Most git deployment methods require the use of bare repositories but I have found that this does not work with projects which use submodules — therefore, we will not be using a bare repository.
cd [folder_name] git init
Next, add your BitBucket or Github repo as a remote (replacing [name] with the actual name you would like for the repo and [URL] with the repo URL from the BitBucket or Github:
git remote add [remote_name] [URL]
Create the Deployment Script
Next, create the following script and make it executable (chmod +x <em>[filename]</em>
):
#!/bin/sh set -eu export BRANCH="master" export REPO_PATH="/path/to/your/git/repo/" export SITE_PATH="/path/to/your/document_root/" # give the user some feedback echo fetch git data from origin echo and rsync from ${REPO_PATH} to ${SITE_PATH} cd $REPO_PATH git reset --hard git pull git checkout -f ${BRANCH} git submodule init git submodule sync git submodule update --force sudo rsync -avz --exclude-from 'exclude.rsync' --delete --force ${REPO_PATH} ${SITE_PATH} # You can continue to add more commands to do stuff like chmod 777 some folders etc...
Above, you may notice these two awesome little snippets:
set -eu
and sudo rsync -avz --exclude-from 'exclude.rsync' --delete --force
set -e
will cause your script to exit if an error occurs and set -eu
means your script will exit if variables are not set (see http://www.alexecollins.com/tips-robust-bash-scripts/ for more details).
This launches rsync
with elevated privileges (I'm not happy with the use of sudo here as it requires you to enter your password every time; if I find a better solution I will post it), --delete
means that any files which have been deleted from the repo will also be deleted from the copied site. The really interesting bit here is --exclude-from 'exclude.rsync'
we haven't covered this yet. It allows us to stop certain files being copied into the website (you can remove it or leave it blank if you don't want to exclude anything). Let's look into this a bit more.
Excludes
Inside your repo, create a file called exclude.rsync
(the name doesn't matter – just change the filename in the command if you want a different one) and in this file, on each new line, name files and folders you don't want copying to the website root. Here is a sample of what to put in this file:
build/ build/* tests/ tests/* .git/ .git/* *.git *.gitignore *.gitmodules *.travis.yml *.sublime-* LICENSE phpdoc.dist.xml README.md exclude.rsync
Well, that's it. However you choose to trigger your script (I ssh into the server and trigger it manually) your site should be deployed flawlessly, every time.
Coming soon
How to backup you site from your NAS…