Technote

Development workflow Intro

Series From local to production Part 2 of 8

What to commit in a WordPress repository, and what to ignore

One rule decides it: did we write this? Credentials and generated content are not source, and once they are in the repository the problem is no longer reversible.

The first question people ask about putting WordPress in Git is “do we commit core?”. But there is a rule that comes before that question: did we write this file? That single sentence decides what to commit, what to ignore, and the handling of secrets in the next part.

Only what you wrote is source

A WordPress directory mixes together things of completely different character. There is the theme, plugins and mu-plugins you wrote; there is core and third-party code you downloaded; there is whatever was generated at runtime — uploads, caches, logs, the upgrade scratch folder; and there is whatever differs per environment, namely wp-config.php.

What stays in the repository and what does not — one test decides it: did we write it?

Notice that wp-config.php, uploads and database dumps sit together at the bottom, and they sit together for the same reason: credentials and generated content are not source. Credentials belong to an environment; uploads and dumps are the output of running the thing. Commit either and the repository stops being a history of code and becomes a copy of data — which then spreads through clones, forks and CI logs, well outside your control.

Build output is a legitimate exception. If you have decided not to install Node on the production server, committing compiled CSS and JS is the right trade. Having made that decision, though, CI has to verify that the output still matches the source — that is part seven.

Two shapes of .gitignore

If core lives in the repository too, you only need an ignore list.

# .gitignore at the repository root
/wp-config.php
/wp-content/uploads/
/wp-content/upgrade/
/wp-content/cache/
/wp-content/debug.log
*.sql
*.sql.gz
node_modules/
.env

If instead the repository holds only your own code and core and third-party plugins are managed on the server, it is safer to deny everything and re-open exactly what you want. Installing a new plugin then cannot quietly pollute the repository.

/*
!/wp-content/
/wp-content/*
!/wp-content/themes/
!/wp-content/plugins/
!/wp-content/mu-plugins/
/wp-content/themes/*
!/wp-content/themes/our-theme/
/wp-content/plugins/*
!/wp-content/plugins/our-plugin/

One rule governs this pattern: you cannot re-include a file whose parent directory is excluded. That is why each level is opened, closed again, and then the specific child re-opened. When you cannot work out why a file is or is not ignored, do not guess — ask Git.

git check-ignore -v wp-content/themes/our-theme/style.css

It answers with the file and line number of the rule that matched.

If it is already committed

.gitignore has no effect on files already tracked. Adding a rule later does not stop them travelling. To untrack while keeping the working copy, remove them from the index only.

git rm --cached wp-config.php
git rm -r --cached wp-content/uploads

But this does not erase the past. The file is still in earlier commits, and if it held a password then that password is already leaked. Tools exist to rewrite history, yet no rewrite reaches the clones and CI logs that already exist. The only real fix is to replace the value — which is exactly the next part.

Repository discipline and the wider deploy flow continue in the development workflow archive, and if you would first like to know what state a site is in, the site diagnostic in our free tools is a reasonable starting point.

Next part

With wp-config.php out of the repository, its values need somewhere to live. The next part covers per-environment configuration and secrets — and the one thing that genuinely undoes a committed secret.

More on this topic

All technotes

Development workflow Practical

Turning taste arguments into rule checks

"It feels a bit cramped" can be neither argued with nor fixed. Spacing off the scale, colour off the palette, contrast below threshold, missing states — four rules…

Designers 9 min read

Development workflow Practical

Do not swap everything at once

A full swap makes every problem appear at the same moment — which means none of them can be attributed. So you switch one template at a time.

Designers 6 min read

Development workflow Practical

Adding an SCSS build, and whether to commit the output

WordPress themes are expected to deploy without a build step, which leads to the opposite conclusion from ordinary application code — and to its own costs.

Developers 7 min read

₩270,000 · Join the program