I’ve shared this script at a few conferences, used it on several servers, and it is still unmatched by most web host’s git deployment methods.

The unique feature of this script is that it performs a two-way sync via git. Most services only handle deployment, pushing local changes to the server. Using an intermediary such as GitLab or Github, this script pushes changes from your desktop to the server, and changes on the server go to your desktop. That’s important when you’re using something like WordPress or Drupal and want to use the one-click updates.


  • This script is super lightweight. If you’re already running a PHP app, why would you want to install Ruby or something else just for deployments?
  • This script, unlike many others, is two-way. That means if you’re running WordPress you can still do you automatic updates right on the server, all while still having the warm sweet safety of a version to roll back to.


  • Setup can be a bit of a pain. You’ll need to set up a git user for your web server, along with proper permissions. If you’re not familiar with command-line git or linux permissions… well then you’re probably not looking for this script to begin with.
  • The only other con is that this script will blindly commit any changes on the server. That includes hacked code. This isn’t always a bad thing though. If you’re keeping an eye on your code, and you should, then you’ll notice when/if the server user makes unexpected commits. If you want, you can even set up alerts. You’ll have to roll back in the case of a hack, but you’ll also be able to very clearly see what code was manipulated. This can go a long way in sealing the hole after your recovery.

Here’s a screenshot of what the end result looks like. Here you can see my usual theme alterations and a few plugin additions, and you can also see the automatic commits from the server. I use a picture of my adorable dog so the cuteness sticks out.



  • Be sure you use a properly configured gitignore file otherwise every cache folder update or file upload will trigger a commit.
  • Add a Cron job to run every so often just to make sure to grab any spontaneous changes on the server.
  • To really leverage this script, kill the use of FTP on your server. In the office we only allow access via Git. It makes managing permissions for projects super easy (just add developers to your repo), and ensures that there’s a record of every code change.


 * This is our Deploy class (do not edit)

class Deploy {

  // A callback function to call after the deploy has finished.
  public $post_deploy;

  // The name of the file that will be used for logging deployments
  // Set to FALSE to disable logging
  private $_log = 'deployments.log';

  //The timestamp format used for logging
  private $_date_format = 'Y-m-d H:i:sP';

  // The name of the branch to pull from
  private $_branch = 'master';

  // The name of the remote to pull from
  private $_remote = 'origin';

  // Relative or absolute path to directory
  private $_directory;

  public function __construct($directory, $options = array())
    $this->_directory = realpath($directory);

    $available_options = array('log', 'date_format', 'branch', 'remote');

    foreach ($options as $option => $value)
      if (in_array($option, $available_options))
        $this->{'_'.$option} = $value;

  // Writes a message to the log file.
  public function log($message, $type = 'INFO')
    if ($this->_log)
      // Set the name of the log file
      $filename = $this->_log;

      if ( ! file_exists($filename))
          // Create the log file
          file_put_contents($filename, '');
          chmod($filename, 0666);

      // Write the message into the log file
      file_put_contents($filename, date($this->_date_format).' --- '.$type.': '.$message.PHP_EOL, FILE_APPEND);

  // Executes the necessary commands to deploy the website.
  public function execute() {
    try {
      // Make sure we're in the right directory

      // Add any untracked files and modifications
      exec('git add -A', $output);
      exec('git commit -a -m"I found changes and committed them"', $output);

      // Update the local repository
      exec('git pull -s ours'.$this->_remote.' '.$this->_branch, $output);

      // Push any changes that were found
      exec('git push '.$this->_remote.' '.$this->_branch, $output);

      // Secure the .git directory
      exec('chmod -R og-rx .git');

    } catch (Exception $e) {
        $this->log($e, 'ERROR');


 * These are options that you can change

$options = array(
  'log' => '/var/www/webozy.net/deploy.log',
  'date_format' => 'Y-m-d H:i:sP',
  'branch' => 'master',
  'remote' => 'origin',

$deploy = new Deploy('/var/www/webozy.net', $options);

If you find any issues, or would like to contribute, please visit my GitLab page.