Beruflich Dokumente
Kultur Dokumente
Bitbucket
Important: Bitbucket have changed how webhooks function, and the technique
described in this post will no longer work without modification. One of my
readers has created an updated version, and I recommend trying that instead. I
no longer use this deployment method and wont be updating my tutorial or
answering comments, but I have left the comment section open so that readers
can post their tips and help each other out.
Git may not have been designed as a deployment tool, but for small projects it
can do the job quite nicely. What makes Git deployments attractive is how
frictionless the process is: make some changes to your project, merge them
into your production branch, push the commit to a remote repository and like
magic the changes are live! Git knows which files need to be changed or
deleted, so you dont have to think about it. If youre already using git to
version control your project then you probably wont even need to modify your
existing workflow, once the initial setup is done.
Prerequisites
Before we get started, check that your server meets the following
requirements:
Git is installed
You have shell access
The PHP exec function is enabled
Most shared web hosting accounts will fail at least one of those requirements,
but if youve got a VPS or dedicated server then you should be good to go.
For the purposes of this tutorial Im going to assume that you have a git repo
already set up on Bitbucket, and that the repositorys directory structure
mirrors your production website. For instance if you want an index.html file
deployed to the root level of your websites public directory, that same file will
exist in the repos root directory.
Im also going to assume that you will be deploying from a branch
named production. In practice you can deploy from any branch other
than master, but its a good idea to deploy from a branch that is not used for
active development, so that you have control over when a deployment occurs.
In my workflow I develop in the master branch, then
merge master into production when Im ready to deploy. Before we get
started, make sure youve made an initial commit to your repositorys
production branch, and pushed to Bitbucket.
Ive tested this process on Centos, but you might need to change directory
paths to suit your own server environment. Whenever you see a variable
inside angled brackets in my in my code samples, such as <repo-
name> or <username>, thats a placeholder that you will need to replace with a
value specific to your own project.
Now that the preliminaries are out of the way, lets get started.
cd ~/<repo-name>.git
GIT_WORK_TREE=/home/<username>/www git checkout -f production
If this is first time youve communicated with bitbucket.org over SSH you may
be prompted to accept Bitbuckets server fingerprint, but if SSH is correctly
configured you wont be asked for your Bitbucket password or a key
passphrase.
// Full path to git binary is required if git is not in your PHP user's path. Otherwise just use 'git'.
$git_bin_path = 'git';
$update = false;
$payload = json_decode($_POST['payload']);
if (empty($payload->commits)){
// When merging and pushing to bitbucket, the commits array will be empty.
// In this case there is no way to know what branch was pushed to, so we will do an update.
$update = true;
} else {
foreach ($payload->commits as $commit) {
$branch = $commit->branch;
if ($branch === 'production' || isset($commit->branches) && in_array('production', $commit-
>branches)) {
$update = true;
break;
}
}
}
if ($update) {
// Do a git checkout to the web root
$commit_hash = shell_exec('cd ' . $repo_dir . ' && ' . $git_bin_path . ' rev-parse --short
HEAD');
file_put_contents('deploy.log', date('m/d/Y h:i:s a') . " Deployed branch: " . $branch . " Commit:
" . $commit_hash . "\n", FILE_APPEND);
}
?>
This script iterates over the payload object sent by Bitbucket, looking for
commits made to the production branch. If any are found, a
git fetch and checkout are performed and the deployment details are logged.
For security through obscurity you might choose to give your deployment
script a difficult to guess name bitbucket-hook-a13jsur5kcidwe89z.php,
for example. The index.php file you created early is also a simple security
measure: it stops anyone from viewing the directory index.
On the Bitbucket website navigate to your repositorys Administration > Hooks
screen and add a new POST hook, pointed
at http:/<domain>/deploy/bitbucket-hook.php.
Deploying
Whenever you are ready to deploy to your web server, merge your
development branch into your production branch, and push the production
branch to Bitbucket. Your custom POST hook will be triggered, and your
deployment script will fetch the repository to the server and checkout the
production branch to your web root.
Hey presto! With one commit your changes have been automatically deployed
to your production web server.
My instructions might look fairly complicated, but after youve followed the
steps once or twice it actually becomes really fast to set up.
Troubleshooting
Here are a few things to check if deployments arent working as expected.
File permissions
You should make sure that the web user (the user that PHP runs as) has
permission to write to your local git repository. The easiest way to ensure this
is for that user to own the repo:
Git path
You may find that you are unable to perform git commands using exec since
the git binary is not in your PHP users PATH. This can be solved by including
the full path to the git binary in your deployment script, for example:
$git_bin_path = '/usr/local/bin/git';
To find where your git binary is located, run this shell command:
which git
Hat tip to Jonathan Johnson for this one. His article might help solve other issues
youre having, too.
Payload
If you need to examine the Bitbucket payload thats being sent to your
deployment script, add the following line to the top of bitbucket-hook.php:
file_put_contents('deploy.log', serialize($_POST['payload']), FILE_APPEND);