I must have read from top-to-bottom more than twenty articles about Git and Wordpress in the last 24 hours, along with all the relevant questions and answers on this Stack site, but most are either too specific (and therefore outdated) to be still relevant or they're concerned with taking a site from local to live rather than the other way around. Most importantly, not a single one includes information on what commands are actually needed for the process, which is a necessity when it comes to something as unintuitive as version control tools are.
I have a site that I developed locally with XAMPP. I then used FTP and the Duplicator plugin to upload the site and database to a shared server. I've been using FTP to make changes since then, and I'd now like to incorporate Git into my workflow to make things more productive/natural. The goal is to be able to transfer the site between my local development server and the production server - without Github or another repository service in between.
However, even as someone with lots of CLI experience, after all the articles I've read and after also having scoured through man git
and man gittutorial
, I'm still very confused about how to use Git to do what I'm trying to do here.
For example, I know that when I'm making changes locally I do git commit
and then git push
to push those changes to the live server, but how do I firstly download the contents of my live server to start working with it locally in Git - do I do git clone
or do I do:
git init
git add .
git pull
What about .gitignore
? I have this sample file to tell me what should go in it, but at which point in this whole process do I create it? And what about the database? I already have a local one setup due to my previous local development environment, so is it still advised to replace that every time with the live one using a tool like Duplicator?
Git as a tool is very, very confusing to someone new to it, and doubly so when you have to take Wordpress into account, so I'm hoping that someone with the experience will be able to distil this stuff into something resembling a guide that tells me what commands I need to run to get my live site to my machine and then up-and-running with Git, as well as to detail any Wordpress-specific caveats.
I initially asked this question with the goal of setting up two repositories: a production one on the site and a local one for development, a workflow for which there's very little guidance or documentation on. Since then I've also come around to the more frequent usecase of including Github in the workflow, for the advantage that it gives of being of an offsite backup for the code.
Git has no problems with being used either way, because it was designed with both in mind, so this is a matter of personal preference, and whether you consider doing git push
twice (to both the production server and Github) a reasonable tradeoff for the extra layer of data security. I've detailed both options below, where each one focuses on propagating an up-to-date version of your live site to all other repositories.
This answer assumes that a local environment and database (whether up to date with the live site or not) have previously been set up due to having been used to develop your Wordpress website locally before taking it live, as was my specific situation when asking this question. If this isn't the case, you'll first need to set up a local environment and database using something like XAMPP before continuing with the rest of this guide.
Additional prerequisites are:
In your Wordpress root directory - where the wp-config.php
file is located - initialise a remote Git repository, and create the .gitignore file:
git init
nano .gitignore
Edit .gitignore to include only the files you want to version control. I use a slightly improved version of Bill Erickson's brilliant sample .gitignore for Wordpress (see the description of my Gist for how my .gitignore differs from Bill's).
Once you've saved your .gitignore file, run:
git add . # Prepare all non-ignored files to be committed
git commit -m "Initial commit"
git config receive.denyCurrentBranch updateInstead
Initialise a local Git repository in your local server's Wordpress root (for example, XAMPP/.../wordpress
):
git init
Configure Git, add the production server as a remote, and finally pull from it:
git config --global user.email "youremail@example.com"
git config --global user.name "Your Name"
git remote add live ssh://user@hostname:path/to/server/repo/
git branch -u live/master master
git pull live
From now on, after making local changes to some files, commit and push them to the production server:
git add . :/ # Prepare all modified and added files to be committed
git commit -m "Message describing changes made in the commit"
git push live
git init
nano .gitignore
Edit .gitignore to include only the files you want to version control. I use a slightly improved version of Bill Erickson's brilliant sample .gitignore for Wordpress (see the description of my Gist for how my .gitignore differs from Bill's).
Once you've saved your .gitignore file, run:
git add . # Prepare all non-ignored files to be committed
git commit -m "Initial commit"
Create a new empty repository without a .gitignore file.
To associate your server's public SSH key with your account: go to https://github.com/settings/keys and click New SSH Key. Do cat ~/.ssh/id_rsa.pub
to output the contents of your server's public key file. Copy this output into the Key field, and save the key.
You'll need to repeat this process for your development machine if it uses different SSH keys to that of your server - or alternatively, you can have your development machine use the same keypair as your server.
Add the Github repository as a remote and push the production site to it:
git remote add central git@github.com:Kaos-Industries/industryroadmosque.git
git config receive.denyCurrentBranch updateInstead
git push -u central master
Initialise a Git repository in your local server's Wordpress root (for example, XAMPP/.../wordpress
) and add the remotes:
git init
git remote add live ssh://user@hostname:path/to/server/repo/
git remote add central git@github.com:Kaos-Industries/industryroadmosque.git
git fetch central master
git merge central master
git reset --hard central/master
git config --global user.email "youremail@example.com"
git config --global user.name "Your Name"
From now on, after making local changes to some files, commit and push them to both the central Github repository and the production server:
git add . :/ # Prepare all modified and added files to be committed
git commit -m "Message describing changes made in the commit"
git push central # Push to GitHub, as a backup
git push live # Push to the production server, to make changes live
Go to the live website's PHPMyAdmin panel, ensure the Wordpress database is selected, and go to the Export tab.
Go to the local server's PHPMyAdmin panel and ensure the Wordpress database is selected. Drop all the database's tables by selecting Check All and then under the dropdown menu, Drop. Go to the Import tab, and import the database file exported from the live site.
Finally, to search and replace the URLs in the database, go to the SQL tab and run the following, making sure to replace the URLs with those of your live site and local site respectively:
UPDATE wp_options SET option_value = replace(option_value, 'https://www.example.com', 'http://localhost/wordpress') WHERE option_name = 'home' OR option_name = 'siteurl';
UPDATE wp_posts SET post_content = replace(post_content, 'https://www.example.com', 'http://localhost/wordpress');
UPDATE wp_postmeta SET meta_value = replace(meta_value,'https://www.example.com','http://localhost/wordpress');
Note that if your live site had HTTPS enabled then explicitly including the http://
protocol before localhost
is required - without it, all pages of your local site will return 404s.
The only thing left to consider at this point is Wordpress' wpcontent/uploads
folder, which I didn't want to version with Git because of how large it is and how much larger it's likely to get. The good news is that uploads don't need to be pulled from the production server at all. Instead, the smarter way to handle this is to use .htaccess
rewrite rules to make missing images on the development site link to their counterparts on production. This cleverly sidesteps the problem of needing to keep the Uploads folder in sync at all.
Add the two lines below to your development site's .htaccess
file, directly after the RewriteRule ^index\.php$ - [L]
line:
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
# If images not found on development site, load from production
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^wp-content/uploads/[^/]+/.+\.(jpe?g|png|gif)$ https://www.example.com/$0 [R=302,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
Note that for the above rewrite rule to work, it's crucial that both your development and production sites aren't sharing a single .htaccess
file (i.e. that the .htaccess
file isn't being tracked in Git). Otherwise you'll need to modify the above rewrite rule to conditionally check whether an image is being loaded from production or development and code separate rewrite rules for each.
Finally, add the following to your active theme's functions.php
file to prevent Wordpress from quietly replacing anything in your .htaccess file:
// Stop WordPress from modifying .htaccess permalink rules
add_filter('flush_rewrite_rules_hard','__return_false');