Git branching workflow for WordPress teams with Gitflow

A good Git branching strategy is the foundation of safe, collaborative WordPress development. Without a defined workflow, developers push directly to the main branch, deployments become unpredictable, and a last-minute bug introduced minutes before a launch can take down a production site. The most widely adopted model for WordPress projects is a variation of Gitflow: a main (or master) branch that always contains production-ready code, a develop branch for integration of completed features, short-lived feature/* branches for individual tasks, hotfix/* branches for urgent production fixes, and release/* branches to stabilise a version before deploying. With this model, no feature code ever touches main directly — it must go through a pull request, code review, and staging environment first. For smaller teams, a simplified trunk-based development model with feature flags (conditions in code that enable new features only for specific users) can work well and requires less branch management overhead. Pairing this workflow with the Git command reference and the automated backup script gives you a production-ready deployment safety net. The commands below implement the Gitflow model for a WordPress project.

Problem: Your WordPress team lacks a consistent Git workflow, leading to conflicts, accidental deployments, and no clear path for hotfixes without blocking in-progress feature work.

Solution: Use the following Git commands to implement the Gitflow branching model:

# ── Initial setup ─────────────────────────────────────────────────────────────
git checkout -b develop main       # create develop branch from main
git push -u origin develop

# ── Start a new feature ───────────────────────────────────────────────────────
git checkout develop
git pull origin develop
git checkout -b feature/custom-checkout-fields
# ... make changes ...
git add -p                         # stage changes interactively (review each hunk)
git commit -m "feat: add company field to WooCommerce checkout"
git push -u origin feature/custom-checkout-fields
# Open a Pull Request: feature/custom-checkout-fields → develop

# ── Merge completed feature into develop ─────────────────────────────────────
git checkout develop
git merge --no-ff feature/custom-checkout-fields
git branch -d feature/custom-checkout-fields
git push origin develop

# ── Create a release branch ───────────────────────────────────────────────────
git checkout -b release/1.5.0 develop
# bump version number in style.css / plugin header, update changelog
git commit -am "chore: bump version to 1.5.0"
git checkout main
git merge --no-ff release/1.5.0
git tag -a v1.5.0 -m "Release 1.5.0"
git checkout develop
git merge --no-ff release/1.5.0
git branch -d release/1.5.0
git push origin main develop --tags

# ── Hotfix a production bug ───────────────────────────────────────────────────
git checkout -b hotfix/fix-checkout-redirect main
# fix the bug...
git commit -am "fix: correct checkout redirect URL"
git checkout main
git merge --no-ff hotfix/fix-checkout-redirect
git tag -a v1.5.1 -m "Hotfix 1.5.1"
git checkout develop
git merge --no-ff hotfix/fix-checkout-redirect
git branch -d hotfix/fix-checkout-redirect
git push origin main develop --tags

NOTE: Use --no-ff (no fast-forward) when merging feature branches into develop and develop into main. This creates an explicit merge commit that preserves the history of when the feature was integrated, making it much easier to revert a specific feature by reverting its merge commit. Squashing all commits in a feature branch (git merge --squash) into a single commit is also common for a cleaner history, but you lose the granular commit messages for that feature.