Working with our Git Integration

If I had to pick one feature of our WordPress platform that I think is really impressive it’d be our Git integration. It sometimes feels like a bit of a secret and when our clients understand its power they typically never look back.

So what is Git?

Git is a distributed version control system, which amongst other things allows developers to share code. It’s a way to track and control files (normally code), keeping versions of files at any given point allowing you to see changes. Version control also has branching, which allows multiple versions of a file to exist at any point. The final big feature of Git is that it’s distributed so the files and versions are stored locally on each person’s machine not just on a central server.

If you are not familiar with storing code in Git, I’d suggest these resources to get you going:

Deploying code with Git

Whilst Git is principally used to store code for collaborative use between developers and maintain a historical record, it can also be used to deploy code to staging and production environments.

When you push and pull content with Git, it has the ability to run scripts and trigger actions, both on your local machine and the origin servers. For instance an trigger can be set on your server to take an action when a commit is pushed to that server.

That action could be almost anything but can be used to deploy code either by executing some tasks on a server or calling a third-party service like deploybot to do the work.

With our WordPress Hosting we have opted for the former, so we have a simple procedure as follows:

  • Run our tool
  • This creates a new repo for you on your container which you can then clone
  • Once cloned you will find a master branch and a staging branch
  • When you push the master or staging branch it will deploy to your live or staging site appropriately
  • Other branches are ignored, they won’t trigger a deploy

The advantage of this solution over us adding ourselves to a third party repo is that it has no outside dependencies; it doesn’t rely on GitHub being up for example. Yet because of how Git works, you can still keep your code in GitHub or anywhere else you want.

So how would this work in practice?

Prerequisites:

  • You will need SSH users for each person who will be committing code 
  • We strongly recommend you set up SSH keys to access your WordPress Hosting account
  • Git needs to be installed on your local machine.

Getting started is as simple as this process:

ssh username@example.com
cd httpdocs
wp git add
exit

git clone ssh://username@example.com/var/repos/example.com

Now you have your repo but by default you’ll see that it’s empty. To add soem content we can do the following:

git add test.txt
git commit -m 'Initial commit' test.txt
git push 

At this stage, you should see a bunch of messages, including how the server’s caches have flushed. This is one of the biggest features of this approach: All the feedback is in the client, including errors, so if there is a problem it will tell you. If we now go to http://example.com/test.txt we will find the text file there, and if navigating to the server we will find it in httpdocs/test.txt

Under the hood here’s what happened:

  • When you push to the origin server, it receives the push request stores it in the repo as normal and then runs a pre-receive process:
  • We take the copy of /var/repos/example.com and copy it to /var/www/vhosts/example.com/tests/ 
  • We then process any pre-receive defined tests if it passes
    The contents of /tests/ is moved to /httpdocs/
  • The post-receive process is then run
  • An internal WordPress action is run to clear the cache
  • Output is fed back to the git client.

What should you store in Git

What you store is up to you, however we would recommend you only store things that are custom and code that won’t be updated via the WordPress auto-updater. 

WordPress items you shouldn’t store in Git:

index.php / wp-load.php

These two files are in your httpdocs root but are not controlled by the user and shouldn’t be stored, they will get overwritten.

wp/

Don’t store WordPress core files, they won’t get pushed to the live server.

wp-content/object-cache.php / advanced-cache.php

These two files are again managed by our hosting and will be overwritten.

wp-content/uploads

This folder is for site-specific uploads and you probably don’t want it in your version control system.

An example Git repo

Our example git repo contains:

my-config.php – Customised my-config.php
wp-content/plugins/ – a few custom plugins
wp-content/themes/example – a child theme

Any plugin or theme from wordpress.org or from a third party with automatic updating is left out of the repo. This improves performance but also means they can update safely. If you do put a plugin into Git that is in the WordPress.org plugins repo, for instance to customise it, then you will need to disable updates for it from your site’s dashboard.

Working with server-side hooks

During the deploy process, there are a few places where we can interact with the deployment. 

Pre-receive

The first of these is the pre-receive location. This test occurs before we deploy the code, but have moved it to /var/www/vhosts/tests/

This can be used for doing things such as linting code, running tests, and codesniffing. It can’t interact with the WordPress database and the code is not live so you can’t make HTTP requests to the code.

To add a pre-receive test you will need to edit /var/www/vhosts/tests/example.com/hooks/pre-receive.sh

This is a simple Bash script which acts as the master process. The only requirement for your tests is that they shouldn’t modify the $status_code variable. Ultimately if that variable is anything but 0  then the commit will be rejected. Any output from the script is fed back to git client.

If the commit is rejected, the git client will be told, and the deploy won’t continue.

Post-Receive

The post-receive hook runs immediately after we have moved the content into the httpdocs folder. This hook is useful for running additional actions. At this stage, the deploy has happened and the files are in place. Examples might be running composer update, running wp-cli commands or making HTTP requests to third parties. 

To add a post-receive process you will need to edit /var/www/vhosts/tests/example.com/hooks/post-receive.sh 

Like pre-receive.sh this is a simple bash script. Unlike pre-receive.sh it doesn’t matter what status code is given though do be nice and try to exit cleanly! As before any output is sent to the git client.

WordPress Action

The last thing to be called is a WP-CLI command, that then has a do_action(‘build_trigger’) within it. This means you can create custom code that will run from within WordPress at the end of a build:

add_action('build_trigger','test');
function test($args){
//run my code after a build
}

For example:

add_action(‘build_trigger’, ‘demo_trigger’);
function demo_trigger( $args ){
  return update_option( 'tn_last_build', time() );
}
add_action(‘core_upgrade_preamble’, ‘demo_build_time’);
function demo_build_time(){
  $last_build = get_option( 'tn_last_build' );
  echo '<h2>'. __( 'Git Deployment' ) .'</h2>';
  echo '<p>';
  printf(__( 'Last Deployed on %1$s at %2$s.' ),
  date_i18n(__( 'F j, Y' ), $last_build ),
  date_i18n(__( 'g:i a' ), $last_build )
 );
 echo '</p>';
}

This would add the last deployed time in the “updates” section of the admin dashboard.

So we have:

  • Pre-receive to accept/decline the deploy
  • Post-receive to run tasks after the files have been transferred
  • Build_trigger hook to process WordPress code after deployment

These 3 hooks can easily be used to do completely control the process, enforce coding standards, run security checks, and more. They can interact with NodeJS to run frontend tooling on the server and just about anything else you would like to do. The post-receive hook can even be used to push your changes into a third party git repository.

Using Multiple git repositories

If you want to setup multiple remote repositories, for example you want to use both GitHub and 34SP repos then you have several options.

  • For smaller teams set up multiple remote origins
  • Use the post-receive hook

By far the simplest way to send to two servers is to setup the remote origins locally at the client-side.

This is done by cloning one repository and then in your local client:

git remote add otherrepo git@otherrepo:/pathtorepo.git
git remote set-url –add –push origin git@otherrepo/pathtorepo.git
git remote set-url –add –push origin username@example.com/var/repo/example.com

With this, a push command will push to both repos, and will still treat the 34SP repository as the source of truth.

The second option is to use the post-receive.sh to then git push into your other repo in a daisy chain. To do this you would need to navigate to example.com/var/repos/example.com on your container and then add the remote codebase as we have done for the first option.

git remote add otherrepo git@otherrepo:/pathtorepo.git

Then within the post-receive.sh you will want get the last commit message and push it to the remote repository.

On the whole, the first approach is a lot safer. If you choose the second approach you might wish to switch the order so that the repository on the end of the chain is the 34SP one, however if you do that you will lose all the benefits of having the output of tests being fed back to you.

In summary

The 34SP.com git integration is simple to setup, but under the hood it has lots of customisation and power to suit almost any setup. Whilst it might feel counterintuitive setting it as the origin server, the benefits of all the feedback coming straight to your git client during a deploy become something you will love. If you are used to git deployments where you have to nervously wait for an email to tell you your commit was rejected then welcome to the future!

Comments

    Sign up to our newsletter

    Get the latest tutorials, videos and special offers from 34SP.com.

    Thanks for signing up!