-4

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.

Context

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.

What I'm Asking For

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.

E_net4
  • 27,810
  • 13
  • 101
  • 139
Hashim Aziz
  • 4,074
  • 5
  • 38
  • 68
  • Possible duplicate of [Git push to live server](https://stackoverflow.com/questions/3728054/git-push-to-live-server) – cabrerahector Aug 29 '19 at 21:53
  • 1
    @cabrerahector How can it be a duplicate of that question when the question is the complete opposite, and therefore the commands are different? I'm a beginner to Git, I don't know what those commands are and I can't be expected to guess based on an answer that explains the inverse process. – Hashim Aziz Aug 29 '19 at 21:55
  • You said "The goal is to be able to transfer the site between my local development server and the production server." How's that the complete opposite to that question? – cabrerahector Aug 29 '19 at 21:58
  • @cabrerahector Yes, that's the *end* goal. Before that, as I mentioned in the body of the question, which I'm sure you read, I need to get the site on my production server down to my machine and set up with Git, which I don't know how to do. – Hashim Aziz Aug 29 '19 at 22:01
  • Well, you could: a) initialize a repo on your server (something that's covered on the linked question), commit changes and then pull to your local setup, or b) download everything via FTP, initialize a repo on your local computer, commit changes, then initialize a repo on your server, push changes from your local repo to the remote repo, etc. The answer I linked above covers the necessary steps to achieve this. Note that, as CodeCaster pointed out below, this only covers syncing files. Keeping a local WordPress database in sync with a remote database is quite another challenge. – cabrerahector Aug 29 '19 at 22:06

2 Answers2

3

Git is not a file transfer protocol. You cannot compare it to FTP, SMB or the likes.

It is not meant to transfer development changes to a live server. It is a revision control system, used to track changes to files.

You cannot "pull" files from your live web server, if that server isn't serving from a shared Git repository. And it shouldn't be.

What Git does, is track files and changes made to those files, in a thing called a repository. What a remote is, is just another Git repository, accessible over HTTP or SSH or other transport protocols, with which you can synchronize changesets applied to either repo.

There is a way to do what you want, and that is to set up your webroot as a Git repository, connect your client to that directory so you can access it locally (SSH, SMB, ...) and do a git pull on the server after having pushed your local changes to the server. But this is just abusing Git to edit files on your live server, and I hope I don't have to explain why that's a bad idea.

But you could, see Using Git to Manage a Live Web Site for some information.

What you need is a shared repository. You use this to push to from your development machine, and at the same time your webserver should (indirectly!) pull from that same repository. Whether you host this repo yourself or in GitHub is up to you. If you do it yourself, and you want to host it on your webserver, make sure to evaluate all caveats, starting at properly configuring authentication.

Now for the development process, you have a bunch of source files that you want to put into Git. That part is trivial: init a Git repo, copy all relevant files into it, including your project-secific .gitignore and add everything in one initial commit.

And for getting your, now tracked by Git, files onto your webserver now and with every change:

  • Make a commit
  • Push it to the remote repository
  • Have a build server configured that gets triggered on commits, or that polls the repo for changes
  • If the build succeeds, let the build server deploy your new site to the webserver

This, in a nutshell, is called Continuous Integration or Continuous Delivery (CI/CD). But that usually doesn't deploy to live servers immediately, but first to a testing environment.

See also: Setting up a deployment / build / CI cycle for PHP projects

As for the database changes, that's a whole different question.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • I'm confused as to why testing changes locally and then pushing them to the server with Git is a "bad idea". I've found this is standard practice in the Wordpress field, and this is the first time I've come across anyone saying it shouldn't be done. Is this not a legitimate way of using Git? – Hashim Aziz Aug 29 '19 at 22:15
  • I've read this answer over again, and I still don't see how using Git in this manner is a bad idea, least of all one that is self-explanatory as this question implies. The more I read about Git the more I'm under the impression that it was designed this way from the ground up - decentralised so as to make a central repository unnecessary - and I've also read that this is the way Linus himself makes use of Git. – Hashim Aziz Aug 30 '19 at 23:52
  • Yes, it is decentralized. That is so you can work offline, without having to be connected to a source server. You do need a remote if you want to collaborate, and if you want to have your source and history accessible from multiple locations or machines. That's a separate issue from your problem. You have a **deployment** issue. Yes, Git can play a part in that, but it was not designed for that purpose. If every change gets pushed to the live server, then that's an disaster waiting to happen. – CodeCaster Aug 31 '19 at 06:57
  • Collaboration and multiple machines aren't an issue for me as a sole developer, and CI/CD are also overkill for me that I don't have the time to look into right now. So in a "standard" setup with a GitHub repository in between, for example, how does deployment look like? `git push` from my local machine to the repo and then `git pull` from the production server? – Hashim Aziz Aug 31 '19 at 19:20
0

Methodology

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.

Prerequisites

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:

Two repositories (production → development)

From the production server

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

From the development machine

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

Three repositories (production → central → development)

From the production server

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"

From Github

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.

From the production 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

From the development machine

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

Keeping the database updated

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.

Dealing with the Uploads folder

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');
E_net4
  • 27,810
  • 13
  • 101
  • 139
Hashim Aziz
  • 4,074
  • 5
  • 38
  • 68