Version Control
We version control all projects at XWP using Git. Version control allows us to track codebase history, maintain parallel tracks of development, and collaborate without stomping out each other’s change

Structure and Package Management

We structure our projects in such a way that we are not version controlling third party code, rather, they are included via a package manager. For PHP, we use Composer to manage PHP dependencies (also see package managers) e.g. WordPress core itself, plugins, and themes. Dependency management structuring is explained more in the Structure section.
We also do not commit compiled files (JS/CSS). This saves us from having to deal with people forgetting to compile files and large merge conflicts. Instead, we generate compile files during deployment.

Git Workflows

It is critical that you are comfortable with Git: read the book! We encourage people to use the command line for interacting with Git. GUI’s are permitted but will not be supported internally. For more information on Git:

Commits

Commits should be small and independent items of work, containing changes limited to a distinct idea. Distinct commits are essential in keeping features separate, pushing specific features forward, or reversing or rolling back code if necessary.
Do not wait more than a day to push commits. Push early and push often. Not only is it important to show progress for our work, it's also important for collaboration — when you sign off for the day another engineer may want to pick up where you left off, or do an early architectural review but that's not possible if you don't pushed up your latest work in progress.
Try to keep your commits as logically self-contained as possible. If you have made a lot of changes which you have not committed yet, you can step through the changes via git add -p to selectively stage chunks for committing. In this way you can group your changes into commits. Using git add -p is also just plain handy to stage changes for commit in general because it helps prevent accidentally committing something you do not intend. For the same reason, git commit -a should be avoided because you don't have the explicit step to review what you are committing. Remember you can do git diff --staged right before commit for one last review.

Commit Messages

The first line of a commit message is a brief summary of the changeset, describing the expected result of the change or what is done to affect change.
1
git log --oneline -5
2
3
# fca8925 Update commit message best practices
4
# 19188a0 Add a note about autoloading transients
5
# 9630552 Fix a typo in PHP.md
6
# 2309e04 Remove extra markdown header hash
7
# 5cd2604 Add h3 and h4 styling
Copied!
This brief summary is always required. It is around 50 characters or less, always stopping at 70. The high visibility of the first line makes it critical to craft something that is as descriptive as possible within space limits.
1
git commit -m "Add an #Element.matches polyfill to support old IE"
Copied!
Separated from the summary by a blank line is the longer description. It is optional and includes more details about the commit and its repercussions for developers. It may include links to the related issue, side effects, other solutions that were considered, or backstory. A longer description may be useful during the merge of a feature branch, for example.
1
git commit
2
3
# Merge 'feature/polyfill' into gh-pages
4
#
5
# matches and closest are used to simplify event delegation:
6
# http://caniuse.com/#feat=matchesselector
7
# http://caniuse.com/#feat=element-closest
8
# Promise and fetch are used to simplify async/ajax functionality:
9
# http://caniuse.com/#feat=promises
10
# http://caniuse.com/#feat=fetch
Copied!
Write your commit message in the present tense: "Fix bug" and not "Fixed bug". This convention matches up with commit messages generated by commands like git merge and git revert. Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
Bonus points are given for starting the commit message with an applicable emoji when the code is pushed to GitHub and the client is OK with them:
    :art: 🎨 when improving the format/structure of the code.
    :racehorse: 🐎 when improving performance.
    :non-potable_water: 🚱 when plugging memory leaks.
    :memo: 📝 when writing docs
    :bug: 🐛 when fixing a bug
    :white_check_mark: ✅ when adding tests

Merges

In order to avoid large merge conflicts, merges should occur early and often. Do not wait until a feature is complete to merge master or develop back into it the branch. Merging should be done as a non-fast-forwards (--no-ff) to ensure a record of the merge exists. However, all merging should be done by means of pull requests, so you don't need to worry about non-fast-forward merges — this doesn't apply to the preview branch, which is a throw-away branch anyway.
If your commits haven't been pushed yet for others to see, it can be a good idea to update your branch from master by means of git rebase master. This prevents your branch from getting cluttered with merge commits from master. Be careful if you rebase commits after having pushed to a remote, as if others have the feature branch on their machines, they will likely get ugly merge conflicts when they try to update their feature branch. This is because git-rebase rewrites the history. (These same cautions go for using git commit --amend.)
When things are absolutely ready to go (i.e. it has passed code review, QA and UAT), we'll then merge the pull request.
When a merge is made into master and the project uses semantic versioning, then the merge should be accompanied by a Git tag.

Protecting the master Branch

We recommend for all repositories to be configured so the master branch is protected to prevent direct pushes. All merges should be made through a pull request, which ensures all code changes are peer reviewed before merging to prevent unintentional code reversions. Additionally, protecting branches provides the following benefits:
    Prevents the master branch from being accidentally deleted by other engineers
    Prevents force-pushes to the branch, overwriting the history

Themes

All new development should take place on feature branches that branch off master. When a new feature or bugfix is complete, we will do a non-fast-forward merge from that branch to staging or preview to verify the feature or fix on the stage environment.
When things are absolutely ready to go, we’ll deploy the feature or fix by performing a non-fast-forward merge from that branch to master

Branching

All theme projects will treat the master branch as the canonical source for live, production code. Feature branches will branch off master and should always have master merged back into them before requesting peer code review and before deploying to any staging environments.
All staging branches will branch off master as well, and should be named preview, staging or stage-{environment} for consistency and clarity. Staging branches will never be merged into any other branches. The master branch can be merged into both staging and feature branches to keep them up-to-date.

Complex Feature Branches

In some cases, a feature will be large enough to warrant multiple developers working on it at the same time. In order to enable testing the feature as a cohesive unit and avoid merge conflicts when pushing to staging and master it is recommended to create a feature branch to act as a staging area. We do this by branching from master to create the primary feature branch, and then as necessary, create additional branches from the feature branch for distinct items of work. When individual items are complete, merge back to the feature branch. To pull work from master, merge master into the feature branch and then merge the feature branch into the individual branches. When all work has been merged back into the feature branch, the feature branch can then be merged into staging and master as an entire unit of work.

Working with WordPress.com VIP (not Go)

Sites hosted by WordPress.com VIP use SVN for version control and deployments. For development, however, we continue to use Git. We do not have SVN commits match 1:1 with the commits in Git, as Git commits are often far more granular than is normal for SVN. Instead, we aim for entire Git feature branch merges to correspond to a single SVN commit. In this way, commits to SVN are analogous Git squashed commits.

Backporting VIP

In the event that VIP makes a change to the repository, we’ll capture the diff of their changeset and import it to our development repository by:
    Grabbing the diff of their changes
    Creating a new vip-XXXX branch off master
    Applying the diff to the new branch
    Commit the changes indicating the Zendesk ticket and the VIP Code Wrangler's authorship (via git commit --author="John Smith <[email protected]>").
    Merging the branch to staging, using a non-fast-forward merge
    Merging the branch back to master, again using a non-fast-forward merge

Deleting or Archiving and Deleting Branches

This workflow will inevitably build up a large list of branches in the repository. To prevent a large number of unused branches living in the repository, we’ll delete or archive and delete them after feature development is complete.

Deleting branches

When projects use non-ff merges to master, we can safely delete feature branches because all commits are preserved and can be located from the merge commit.
    Move to another branch (doesn’t matter which): eg. git checkout master
    Delete the branch (both on local and remote): git branch -D branch-name; git push :branch-name

Archiving and Deleting branches

When projects use squash merges to create a more streamlined history in master, we should archive branches before deleting them to preserve the commit history. Branch tag archives also prove a useful history of branches, in case a specific branch is needed later.
    Move to another branch (doesn’t matter which): eg. git checkout master
    Archive the branch: git tag archive/branch-name branch-name
    Delete the branch (both on local and remote): git branch -D branch-name; git push :branch-name
    Push the archive tag: git push origin archive/branch-name

Plugins

Unlike theme development, the master branch represents a stable, released, versioned product. Ongoing development will happen in feature branches branched off a developbranch, which is itself branched off master. This pattern is commonly referred to as the Gitflow workflow.

Branching

New features should be branched off develop and, once complete, merged back into develop using a non-fast-forward merge.

Deploying

When develop is at a state where it’s ready to form a new release, create a new release/<version> branch off of develop. In this branch, you’ll bump version numbers, update documentation, and generally prepare your release. Once ready, merge your release branch (using a non-fast-forward merge) into master and tag the release:
1
git tag -a <version> -m "Tagging <version>"
Copied!
Note: Once a version is tagged and released, the tag must never be removed. If there is a problem with the project requiring a re-deployment, create a new version and tag to reflect the change.
Finally, merge master into develop so that develop includes all of the work that was done in your release branch and is aware of the current state of master.
You can use the svn-push script in wp-dev-lib to facilitate the syncing of plugins to WordPress.org. This integration can even be automated by Travis CI.

Semantic Versioning

As we assign version numbers to our software, we follow the Semantic Versioning pattern, wherein each version follows a MAJOR.MINOR.PATCH scheme:
    MAJOR versions are incremented when breaking changes are introduced, such as functionality being removed or otherwise major changes to the codebase.
    MINOR versions are incremented when new functionality is added in a backwards-compatible manner.
    PATCH versions are incremented for backwards-compatible bugfixes.
Imagine we have written a new plugin. We might give the first public release version 1.0.0. After releasing the plugin, we decides to add some new (backwards-compatible) features, and subsequently releases version 1.1.0. Later, we find a bug and report it via GitHub; no functionality is added or removed, but we fix the bug and releases version 1.1.1.
Down the road, we decide to remove some functionality or change the way some functions are used. Since this would change how others interact with this code, he would declare this new release to be version 2.0.0, hinting to consumers that there are breaking changes in the new version of his plugin.

Change Logs

If your plugin is being distributed, it’s strongly recommended that your repository contains a CHANGELOG.md file, written around the Keep A Changelog standard.
Maintaining an accurate, up-to-date change log makes it easy to see – in human-friendly terms – what has changed between releases without having to read through the entire Git history. As a general rule, every merge into the develop branch should contain at least one line in the change log, describing the feature or fix.
Last modified 2yr ago