/ Development, Processes

How to manage your WordPress codebase with Git

This article instructs how to set up your own WordPress (selfhosted) Git project using BitBucket. It is a common and affordable service from Atlassian and will be used as your remote repository. The covered use case is instructing how a single user can connect their development and production environments using a Git remote server.   

Short history: Git was created in 2005 by Linus Torvalds, the same Finn who came up with Linux. Linus ended up creating Git for his own needs to have an open source, functional source control management for Linux kernel development.

Git is currently the de facto standard solution for version control management in software development. Git tools can be found in most development environments in various operating systems. They allow convenient version control, adapting flexibly to different use cases, particularly but not exclusively multi-user developer.

Git is not a backup solution! If you only need to have your files somewhere safe and sound, there are better options around. Particularly, you even shouldn’t store all files necessary to run WordPress in a remote Git repository for security reasons.

Idea of version management

Version control systems solve the problem in software development of keeping track what you and everyone else working on a project have done. It enables you to record and control the history of a code base. It can do this for multiple people at the same time and manage situations where people do conflicting changes to code.

To achieve this, version control system, such as Git or SVN, takes care of all the inconvenient bits for you. When using git, it helps to control the flow of source code between development, staging and production environments and their subsections (aka branches).

Git thus enables several people, even total strangers, to contribute to a common project without much manual hassle of tracking changes. Individual coders make so called pull requests (PRs) to indicate that they have something to contribute to the common good. If there are any conflicting changes they need to be resolved before the contributions can be merged (combined).

Even if you’re working on a solo WordPress project, Git can reduce anxiety in versioning and updates, and help to maintain awareness of what has happened in your setup, when and why.

For newcomers to version management, I should stress that unlike Google Drive, Dropbox or Box, Git is not an automatic versioning system. It is manual, requiring you to specify what you want to version, and when and how to do that. Commands called add and commit are used for that purpose.

Getting started: creating a repository

When using Git, you’ll be moving code between at least two repositories. The other is likely your production or development environment (depending on whether you’ve already published your software) and the other is a central Git server.

In this guide, I’m referring to BitBucket remote server for the reason that it offers free, private repositories. GitHub is another good option if you are developing a public, open source project. Both are git servers and offer functionalities that are not available in the standard command line tool.

I’ll explain step by step how your source code goes through a working space (directory) to a local index, local repository and then to the remote repository.

Step 1. Your server environment

TL;DR commands needed to pass steps 1 + 2:

git init

# setup .gitignore

git add .

git commit -m “Message”

git remote add origin https://username@bitbucket.org/username/your-repo-name.git

git push -u origin master

I highly recommend that you read through the guide in order to get the big picture!

Let’s assume your development/production repository resides in a Linux/OSX environment and you’ll use common Git command line tool (try command git to check you have the tool installed) inside a command shell to use it.

You’ll start from the root of the WordPress installation directory, use cd to get there. This is the directory that contains wp-config.php file – among many others (for me, at least 30 files).

Then you set up the local repository :

git init  

Then you can try

git status

To preview how git sees your installation directory. It has done nothing this far. Next step is to add the files from WordPress installation to the repository.

Now, with a WordPress project, you want to exclude some of the stuff inside the installation directory. Things such as passwords embedded in WordPress configuration, any of the stuff in wp-content/uploads or cache files are best left outside.

To exclude those files, we’ll create a .gitignore file and list all excluded files in there. I will create the file here by summoning nano, a simple text editor I’ve accustomed to (and which provides straightforward instructions for its keyboard shortcuts…).

Please feel free to use emacs, vim or anything else you may desire, the only thing that matters is the filename under the working directory

nano .gitignore

Now, you may enter files and directories one by one into the ignore file. I exclude the following:

wp-config.php
wp-content/uploads
wp-content/cache

Now, save the .gitignore and close the editor.

Why you need to do this? The wp-config.php contains unencrypted credentials which you should never store in a repository. Uploads directory has swallowed all of your content files, images, documents and so forth, which don’t belong to a code repository because of their function and stable nature. I’ve excluded the cache directory created by W3 Total Cache plugin as well because it gets automatically regenerated whenever the site changes.

Now your local repo setup is good to go. Next we add all files under the working directory into it. Command

git add .

Will do just that. This takes a little while to do this at the first time. This adds all files (indicated by . ) to the index of your local repository from your workspace, the directory.

Now try again

git status

You should see there are quite a few new files in your index that are about to fall into your local repository. Currently they are in an index, called staging area. To be specific, this refers to .git/index file that tracks files belonging to the index.

Image result for git

Schematic illustration of how code moves from the working directory towards the Remote repository. Source: Wikimedia

To finally include them in your repository, you need to commit them first. Commit is an action that transfers your changes from the working directory and index to the local repository. This is how to do that:

git commit -m “Message telling what you’re adding to the repository. E.g. initial commit”

Although maybe tempting, leaving out the commit message is not possible. Try that and you’ll only end up in your default editor to create one (and I hope the editor is something familiar to you).

After your commit has happened, try git status once more. There should be no changes and nothing to commit.

There you have it! Your local repo is done! However, now you probably would like to sync your repo to the remote git server.

Step 2. Setup git server from BitBucket

TL;DR commands:
git remote add origin https://username@bitbucket.org/username/your-repo-name.git
git push -u origin master

To start using BitBucket you need to register at BitBucket for an account. With your account, you can start creating repositories.

After you have successfully registered, go ahead and create your new repository. I suggest a short but descriptive name as you will need it every now and then. The type of repository should be git.

Dialogue for adding new Git repository

After creating the new remote repository, we need to connect these two. That happens in your server environment. BitBucket kindly offers you the magic words necessary to this.

Go and look under Overview → Get started → I have an existing project (that’s how it read in March 2017). The necessary piece of code is something like

git remote add origin https://username@bitbucket.org/username/your-repo-name.git

BitBucket helps you to start filling your empty repository (Screenshot 20.3.2017)

Once you copy paste this line of code into your terminal, your local configuration changes. This commands changes your local git configuration so that there is a remote destination available. We name this remote origin and tell git to find it at the address starting https…

Nothing else happens with this command, no interaction with the remote yet. You can see your newly added remote with  the command

git remote -v

But now we want some action. So let’s push the new files we have committed to our local repository to the just created remote end point. The command needed is:

git push -u origin master

Now you will be prompted for your BitBucket password for the account you just created. After you authenticate yourself successfully, you’ll see a summary of your WordPress files being uploaded to BitBucket. It could look something like this

$ git push -u origin master

Password:

Counting objects: 684, done.

Delta compression using up to 2 threads.

Compressing objects: 100% (670/670), done.

Writing objects: 100% (684/684), 33.22 MiB | 1.06 MiB/s, done.

Total 684 (delta 72), reused 0 (delta 0)

To https://username@bitbucket.org/username/your-repo-name.git

* [new branch]      master -> master

Branch master set up to track remote branch master from origin.

What the last command did was to copy (push) your changes in the local master branch to the remote location we named origin.

Wohoo! You’ve done it now, your Git setup is up and ready (assuming everything went well).

I was about to say ‘up and running’ but that is against the nature of git. Git does nothing on its own. You have to ask if you want it to do something.

Step 3. Useful optional settings

To make your life with git easier in the longer run, it’ll be useful to do bits of further setup. They are

  1. Setup your user names
  2. Setup SSH certificate to identify your transactions instead of HTTPS

Setup usernames

Username configuration is easy and avoids git nagging you about an incomplete setup.

git config --global user.name "Your Name"

git config --global user.email you@example.com

This information will show up at the git server when you push stuff there.

Setup SSH certificate to identify your transactions instead of HTTPS

As you noticed when you did your first push, you always need to enter your BitBucket password to succeed. If you develop your WordPress everyday, repeated password entry may be annoying. Or if you use it seldom, you may forget it. Luckily you can bypass this by setting up SSH key identification without a passphrase, which replaces the standard identification method.

This is bit tricky, but not impossible. Next follows a short guide, see BitBucket documentation for a longer version. It’s about creating a sustainable identification method from your production environment to the server.

The easiest way is to create a pair of public and private keys on the server with the command and leave the passphrase empty!

The empty passphrase is generally considered as a bad practice, here’s a good explanation of alternative, more secure and almost as convenient solutions.

Let’s create the keys next:

ssh-keygen

What follows is something like this

$ ssh-keygen

Generating public/private rsa key pair.

Enter file in which to save the key (/home/username/.ssh/id_rsa):

Created directory '/home/username/.ssh'.

Enter passphrase (empty for no passphrase):

Enter same passphrase again:

Your identification has been saved in /home/username/.ssh/id_rsa.

Your public key has been saved in /home/username/.ssh/id_rsa.pub.

The key fingerprint is:

12:23:34:45:56:56:67:78:89:db:dc:a2

username@green01.kryptoniitti.com

The key's randomart image is:

+--[ RSA 2048]----+

|      +          |

|        ..*oo.   |

|        .+EBo..  |

+-----------------+

Next you can check that the files got created

 

ls -a ~/.ssh/

You should see at least

.  ..  id_rsa  id_rsa.pub

That’s enough. The other part of the system is now set up. Next thing to do is to hand over your public key id_rsa.pub to BitBucket so it can identify you (always keep your private key to yourself). You can get the public screen displayed on your screen for instance with the command:

cat ~/.ssh/id_rsa.pub

It looks like:

ssh-rsa WBQKa...2056..random...characters....R2d37B== username@your-server-domain.com

This public key has to be stored in BitBucket under your account. So return to the web browser and https://bitbucket.org/account/user/username/

You’ll find your BitBucket settings under the avatar menu in the upper right corner. SSH Keys reside under Security section. Copy your key using the Add key function.

Git profile’s SSH keys section
Add SSH key input field

That’s nearly all. The key exchange is ready, but git won’t use it because the earlier configuration was different.

Final step is to change the local git configuration so it will change from HTTPS to SSH. You’ll find the new settings in BitBucket from your Repository, by peeking into Clone action which should now automatically propose the new method. If you copy the line highlighted in the screenshot, you’ll see that it looks like this:

git clone git@bitbucket.org:username/your-repository.git

The essential part is the third word:

git@bitbucket.org:username/your-repository.git

You’ll need to change this bit into your git configuration file, located in .git/config (relative to your working directory). It should look like this

cat .git/config

[core]

            repositoryformatversion = 0

            filemode = true

            bare = false

            logallrefupdates = true

[remote "origin"]

            url = https://username@bitbucket.org/username/your-repository.git

            fetch = +refs/heads/*:refs/remotes/origin/*

Open up your editor and find the line starting url go and replace the “https…” part with the

git@bitbucket.org:username/your-repository.git

Once you save and close the file, your further attempts to push anything to BitBucket will happen without a password!

When you try this the first time, you’ll be asked to confirm the connection to BitBucket (unless your environment was already configured for access)

$ git push

The authenticity of host 'bitbucket.org (104.192.143.3)' can't be established.

RSA key fingerprint is 97:8c:1b:f2:6f:14:6b:5c:3b:ec:aa:46:46:74:7c:40.

Are you sure you want to continue connecting (yes/no)? yes

Warning: Permanently added 'bitbucket.org,104.192.143.3' (RSA) to the list of known hosts.

Counting objects: 19, done.

Delta compression using up to 2 threads.

Compressing objects: 100% (10/10), done.

Writing objects: 100% (10/10), 1.31 KiB, done.

Total 10 (delta 9), reused 0 (delta 0)

To git@bitbucket.org:username/your-repository.git

  1a53310..ecacada  master -> master

 

You’re good to go now.

I’ll next introduce few ways to use git.

Using Git as a part of a normal work

Once set up, git is only useful when you actually use it in development. The internet is full of guides and even free books on how Git works, so I will only cover three basic scenarios here that will get an individual WordPress hacker started.

In WordPress, there are several components that can change your codebase without you touching a line of code. Updating, installing and removing plugins or WordPress core will make changes to your installation.

To keep up with the changes you need to go through a process of adding and committing files to a local index, and then pushing your changes to the remote repository (here, BitBucket).

So, most of the time, you’ll do add, commit, push – assuming everything goes fine. But here are few use cases that you’ll run into:

  1. Reverting unwanted local changes
  2. Create a local WordPress development environment from Git server
  3. Development branching

Reverting unwanted local changes

Say you accidentally introduce a bug in your code, which you can’t fix – or overwrite the whole file with lorem ipsum. Git helps you to get back to an earlier state in the history with little effort.

Git keeps a local copy of all files in the repository with their changes. You can go back in the history for all files in the repository, or just select few. The command you’ll need is checkout which basically means that you’ll want to change files in your working directory to those found in a specific commit. For instance:

git checkout -- README.md

Would restore (checkout) the version of README.md you committed last to your local repository.

Create a local WordPress development environment from Git server

It is very simple to make new copies of the repository in new environments. You’ll start by cloning the remote repo. You can find the necessary command from BitBucket clone. First enter a directory under which you’d like to establish your repository. Then issue a command like this:

git clone https://username@bitbucket.org/username/your-repository.git

git pull

This causes git to replicate your-repository from BitBucket locally and then fetch all associated files there as well. BitBucket password will be required unless you set up a public key identification.

Your development environment is not complete after this, however. You’ll still need to recreate the wp-config.php file locally and setup the MySQL database. As those are better not done via Git, you need to use traditional methods (sftp, ssh) to transfer your data.

As a consequence, it is normal to have your development or testing environment to utilize different data than your production environment. This shouldn’t cause big trouble, if some confusion when seeing old data in development.

Development branching

When several people work on a share project, branching the project becomes a standard practice. The magic word is checkout which refers to pointing out some branch of development and saying that you want to use a chosen historical state to change your working files.

In a single user WordPress project the usefulness of branches is questionable, but it might become handy sometimes. For example if you want to, say make modifications over a long-term to a WordPress plugin without committing them production while doing quick development changes elsewhere which you need to commit.

In branching you create parallel development tracks called branches which you can check out as needed. Here’s what you need to start (read more here). Let’s create a test-branch

git branch test-branch

You can view your branches with the command:

git branch

Output shows that you now have two branches:

* master

 test-branch

The asterisk indicates the branch you’ve currently checked out. Let’s switch that:

git checkout test-branch

Running git branch now will reveal that you are currently working with the test-branch.

 master

* test-branch

As you continue working, your changes will be added and committed to the test-branch, instead of the master.

Go ahead and change something like the README.md, add and commit your changes.

After committing your changes, you can switch between branches, if there’s a need to temporarily discard you work. Going back to master enables you to push new changes to remote server while keeping your local changes in your local branch.

You could push changes to the server, but if it’s your own project, that’s likely unnecessary. But, once you’re done developing your plugin you will want to do that. The magic action is called merge. It will join the working branch the with the master branch.

The logic of merging is to switch to the branch to which you want to join the changes to and then merge the change:

git checkout master

git merge test-branch

$ git merge test-branch

Updating ecacada..abbf03d

Fast-forward

README.md |    1 +

1 files changed, 1 insertions(+), 0 deletions(-)

If you have made any changes that create a conflict, you will be prompted to deal with them before merge can be completed. Conflict means that there are differences in code on the same line in the same file.

Now you can update the remote server simply by pushing your most recent branch:

git push

Now your local and remote master branch will contain your updated README.md!

If you feel that this branch has now served its purpose, you can remove it from your local git. This will preserve the change history because it is contained in the commit.

git branch -d test-branch

That’s all, you can easily find answers to your git questions from the web once you know the basics.

Learn more

Useful supplementary tools:

Sourcetree – visually track and control your versions (Windows & Mac)

SCMbreeze –  shell (Linux, Mac) tools that make your life with Git easier in terminal environment

 

http://stackoverflow.com/questions/36922197/how-does-git-status-work-internally

Thanks to Mikael Blomberg, Principal Software Specialist at SC5, and Iikka Winter, Lead Developer at SC5, for their help with the article.

Text: Lassi A. Liikkanen, Data-Driven Design Specialist at SC5, @lassial

Visuals: Joonas Haverinen

Learn our ways of working.