Technote

Development workflow Practical

A .gitignore for WordPress on GitHub

The line between what belongs in a WordPress repository and what must never enter it is sharp. The moment wp-config.php lands in a repo, your database password and auth salts ship with it.

Putting WordPress under version control by adding everything is how the accident starts. Core, uploads and configuration all live in one tree, so the first job is to draw the commit boundary. This is the rule set we actually use when moving client sites to Git.

The boundary, in one picture

One question decides everything: if this file were lost, could code recreate it? If yes (core, vendors, caches) — ignore it. If no (the theme and plugins you wrote) — commit it. The single exception is secrets: irreplaceable, and still never committed.

Only the code you wrote stays in the repository

Why wp-config.php comes first

It holds the database password and all eight auth salts in plain text. The moment the repository goes public — or a private repo leaks a single credential — everything needed to forge sessions for the whole site ships with it. We have inherited sites where a plaintext DB password sat committed in version control for years. Keep only wp-config.sample.php in the repo; real values are created on the server at deploy time.

A committed secret is not erased by a delete commit. It stays in history, already copied into every clone. The only real response is to revoke and reissue the values themselves.

A working .gitignore

# Secrets — never
wordpress/wp-config.php
.env

# Core — reproducible from a version number
wordpress/wp-admin/
wordpress/wp-includes/
wordpress/wp-*.php
wordpress/index.php

# User artefacts and runtime
wordpress/wp-content/uploads/
wordpress/wp-content/upgrade/
wordpress/wp-content/cache/

# Build and tooling
node_modules/
*.sql
*.log

Pinning core without committing it

Record the version number instead of the files. A deploy script running wp core download --version=X.Y reproduces the same tree on any server. Committing core bloats the repository and turns every core update into a thousand-file diff that buries the review of your own code.

Core is managed as a version number, not as files

If it is already committed

  • Secrets — rotate the DB password and reissue salts now (api.wordpress.org/secret-key/1.1/salt/). Cleaning history is the second problem.
  • Large files — remove them from history with git filter-repo; plan for a full re-clone if you collaborate.
  • From today — add the .gitignore, then git rm -r --cached to stop tracking without touching the server.

Drawing this boundary is half of a deployment workflow. The other half — shipping exactly what staging verified — is what our work process documents, and the full service is described in the optimization program.

More on this topic

All technotes

Development workflow Advanced

Running WP-CLI in CI: what the checks actually look like

Checks that rely on somebody remembering get skipped in a busy week. Stack the cheap ones first, run the rest against a disposable WordPress, and the remembering stops…

Developers 8 min read

₩270,000 · Join the program