Here’s the setup. You’re a good little developer and you’re building your latest WordPress Theme using git to track your changes. You’ve got a local environment where you develop and test edits to your theme file but you don’t have a good way to push those changes to the server. Yesterday I was doing my development using git but using FTP to send updated files to the server, today I simply use
git push. Here’s how:
I assume you know a bit about git, aren’t confused by the term SSH, and can work on the command line. What we’ll be doing here is setting up a remote repository on your server, setting it as a remote on your local git project, and configuring a git “hook” to move files to a particular directory on your server when you use git push.
When we are done your workflow will look like this:
git commit -m "latest changes" git push dev-server master
Then your remote server will have the latest changes! Here are the steps:
- Create a folder on your server where you’ll keep “bare” git repositories
- Init a “bare” repository for your project
- Configure the
post-receivegit hook to send the latest files to the deployment directory
For the purpose of this example let’s assume the project I’m working on is call “goodgoodproject” and it’s a wordpress theme. I have a local development environment I’ll refer to as “local” and a server that I’ll refer to as “remote”.
If you run into problems, I’ve added a “gotcha” section at the bottom.
Set up the remote server
First thing you’ll need to do is get SSH access to your server. Once you have that I would recommend setting up your
~/.ssh/config it saves so much time, read more about that here. I’ll use normal syntax throughout the tutorial though.
Connect to your server, it would look something like this:
If you use a port that command might look like this:
ssh -p 22000 firstname.lastname@example.org
Once you’re on your server create a folder in your home directory where your git repositories will live, I called my folder
git/ but you could call it anything. We’ll make a empty directory using the
mkdir (make directory) command.
Now we want to make a repository for the “goodgoodproject”, let’s change directories using
cd (change directory) command.
This leaves us in our new folder at
~/git/. Next we will use the
git init command to initialize a new git repository, but pay attention to what I do here:
git init --bare goodgoodproject.git
I’m initializing a “bare” repository, this means that there aren’t working files just the bare essentials that make up a git repo. I’ve also added
goodgoodproject.git to the end, this tells git to initialize a bare repository in a directory of that name. I use the dot git ending just so I can indicate that this directory contains a git repo, you can names yours anything.
Create your deployment directory
This is the directory (on your remote server) where you want your code to end up. In our example I’m working on a WordPress theme called
goodgoodproject. So I want it to be in the
wp-content/themes/ folder in my web directory on my remote server. Your server might be different so be aware of where you want to write your files! My public html file is where I’ve install WordPress so to create my deployment directory I’m going to use the make directory command like so:
Now there is an empty folder where the files from my git repo will be placed when I deploy them from my local machine!
Setup the post-receive hook
Git has these “hooks” which allow you do perform special action based on actions taken by or upon the git repo. The post-receive hook is activated when git push is done on the repo. This will become more clear as we go on.
First let’s change directory to the
hooks folder of our new repository on our remote server.
We are going to create a file in this directory called “post-receive” and put some content in it. To do this we simply have to open the file with a text editor from the command line. I like using
nano but you could use
vim or anything else.
nano is the program on my server (and most UNIX servers) that allows me to edit text, so we’ll use this command:
We are now in the nano program, it should be mostly black, no text on the inside. We are going to write this simple little
sh script. I’ve added comments after
# hashtags, these aren’t read by the script, they are for your reference. Except for the first line, the
#!/bin/sh is called a hashbang, it tells the computer how to run the following file.
#!/bin/sh # the target is the deployment directory we created earlier TARGET=$HOME/boomtown.goodgoodwork.io/wp-content/themes/wp-theme-boomtown # the GIT_DIR is the directory where our git repo we made is GIT_DIR=/home/goodgood/git/boomtown.git # this is the command we want to run when this hook is fired git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f # finally anything we echo will show up as a message on our local machine when we push to our server! echo "latest files moved to $TARGET"
A quick note, the
$HOME variable is the same as
~ it expands to the home directory of the user. The above code is for a
sh script, or shell script. This means that when the
post-receive hook files we are simply running a shell script on the server, this means you could do loads of cool stuff when you push to the repo. Right now we are simply running the following command:
git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f
This is simply using the
git checkout -f (force checkout) to put files from the
git-dir HEAD into the
work-tree path. I’ve used the variable
$GIT_DIR to make the code a bit more readable and easy to edit.
Now we save our file. With
nano you will press
Ctrl+V it will ask you if you want to write, press
y then return. Finally we need to make sure our new file can be executed! We are going to run the
chmod or Change Mode command on our new file and set it so it can be executed.
chmod +x post-receive
That’s it, now we are ready to go back to our local environment.
Setup the local git repo
I’ll assume you’ve already got your local git repo set up, navigate to that folder. We are going to add a remote repository! From our git repo on our local machine we are adding a remote named
server you can, however, name it what ever makes sense to you!
git remote add server ssh://email@example.com:22000/git/goodgoodproject.git
This looks a bit complicated, let’s break it down. The first part is a normal git command to add a remote repo, you’ve probably done this with a service like github.com, that’s the
git remote add server part.
Let’s look now at the remote url we are using. It starts with
ssh:// this simply tells git to use SSH as the protocol for connecting to the server. Next comes the
username this is what ever your SSH account’s user name is. Then we have
@hostname.com, typically this is the server’s web address, but it might be the IP address. Followed by
:22000, this is the port, sometimes you need a port, sometimes you don’t, I just wanted to make sure you knew what it looked like. After that we have
/git/goodgoodproject.git you should recognize this as the path to the git folder you initialized earlier!
Because I use an ssh config alias my remote url is much easier:
git remote add server goodgoodwork:git/goodgoodproject.git
Just remember that you need a colon between the SSH address and the path to your remote git repo.
Great, now the local repo has a new remote called
server. All you’ve got to do now is push to it!
git push server master
This will push the
master branch to the
server url! Once it lands on the server a program called
git-receive-pack will trip the
post-receive hook and fire the shell script to add the files to our deployment directory!
There are a few places where things could go awry, let’s look at them:
git-receive-pack: command not found
You do your git push from the local machine and get the following error:
bash: git-receive-pack: command not found fatal: Could not read from remote repository.
This means that the
git-receive-pack command couldn’t be found on the remote server. I use Namecheap hosting (and so should you) which for what ever reason do not add this command to the
PATH by default. They provide a simple fix where you add the folder where 3rd party programs live on their server to your PATH file via
.bashrc file. I won’t go into that, but you should be able to figure out a solution to your environment based on this.
You need to test if git push works
When I was setting this up I kept running into the problem where I’d do a git push, something wouldn’t work, I’d fiddle around on the server then want to test again but when I did another git push I’d get:
There was an easy way to get around this, just add a dummpy commit:
git commit --allow-empty -m 'push to execute post-receive'
It adds useless commits to your history, but who’s paying that any mind?
I hope you found this helpful, if you learn of any more gotcha’s I’ll add them. I would love to hear how other people use this and other hooks.
Oh yeah! I also wrote a little bash script that you can put on your server to generate these git repos with ease.