How we use git and Github to build Nexu.mx
Developing new software and efficiently collaborating with other team members is not easy to the newcomer to a distributed version control system. Hell, even a skilled developer with knowledge of git
, can struggle to make his current git
workflow fit into a new team.
After seeing our repos heading towards quantum entanglement, I decided action was needed. I dug deep into best practices for using git
and Github, and looked into several team’s workflows without finding something that would work for us.
The git-flow
, proposed by Vincent Driessen seemed a bit of an overkill for our needs at the time. Don’t get me wrong, I think it is great. I just think that it might baffle developers who are just starting to get a hang of how git
works and believe it works best with larger, more complex, yet more structured teams than what we had at Nexu.mx at the moment.
I later came across the Github flow (TL;DR). Scott Chacon explains how Github uses git
to build Github using a simplified version of the git-flow
. We derived our workflow from the Github flow, albeit with some small modifications and configuration tips, to help developers get on board with git
and Github at Nexu quickly.
The Nexu-git-flow
1. Master
is always deployable
This is the core of the Nexu-git-flow. master
should always be in a deployable state. Code in master
is in production or will be in production soon. This branch does not allow for any direct modifications. To achieve this, we leverage protected branches on Github.
Branch protections allow us to prevent anybody on the team from working directly on master
. New code must come from a development branch and always be reviewed before being merged into master
. We set up our master branches to be protected using the following settings:
- Require pull request reviews before merging
- Require status checks to pass before merging
- Require branches to be up to date before merging
We’ll eventually also add a restriction to require Continuous Integration (CI) tests to pass before merging.
2. Development branches
To start coding, Nexu developers create new branches from the latest commit on master
. New code goes there and we agree to commit early and push often, so everybody can get their hands on new code ASAP.
To keep history as clean as possible, avoid unwanted merges, and make typing commands a bit faster, we encourage developers to use the following global git
configuration:
Specifically, pay close attention to the branch.autosetuprebase
and pull.rebase
options. This basically sets up rebasing for new branches automatically and makes every pull from the repository rebase your local changes, instead of forcing a merge caused by diverging commits on the same branch (a problem often encountered in our early days).
New branches should be named descriptively. Names should be short, uncapitalized, and hyphenated to keep our branch naming style consistent. To create new branches, correctly set up branch tracking, and push them to Github, we encourage developers to adhere to the following workflow:
$ git checkout master
$ git pull
$ git checkout -b development-branch
$ git push -u origin development-branch... start commiting and pushing ...
3. New commits go in development branches
We always create new commits on development branches and never on master
. Rewriting commit history is allowed on development branches, taking the necessary precautions not to affect anybody else’s work on that branch. Force pushing a development branch should be avoided, but is allowed when it significantly improves commit history on the branch.
Workflow in a new branch looks as follows:
$ git checkout development-branch
$ git pull... local changes ...$ git commit -m “Adds certain functionality”
$ git pull
$ git push
Pay special attention to commit messages. A commit message should be short, descriptive and complete the sentence This commit ______ . This means the first word of a commit is always a present tense verb in third person singular form (Grammar Nazi much?). We always capitalize the first word of a commit message and never punctuate them. This maintains a consistent style when going through git logs
.
4. Code review in pull requests
At the beginning, we struggled for a way to review code. Going over each new commit a developer made was hell. Github provides the ideal environment to review other developer’s code: Pull Requests. We just wish we’d learned about it sooner.
Once we’ve pushed code on our development branches to Github, we simply create a new Pull Request (PR) on the Github web interface, specifying master
as the base branch, and our development branch as the compare branch.
We then go on to set assignees to indicate people who should also work on that PR; reviewers to indicate who you want to review your code; and a milestone to indicate the sprint the PR belongs to.
PRs allow a conversation to take place while reviewing code and provide a timeline of changes to the branch to be merged. Furthermore, branch protections on master
block merging until at least one approved review is obtained and the branch is up to date with master
.
5. Merging Pull Requests into master
#NexuDev committed to not only requiring one approved review on the branch, but requiring approved reviews from a majority of team members before merging a PR; unless it is a simple hotfix which urgently needs to be deployed. This has helped us improve the quality of our code drastically and make developers actively involved in features they might not have been originally assigned. Of course, this might not scale well for a larger team. When that happens, we’ll most likely split the team into development pods, each of which would follow the same workflow in an independent, yet coordinated fashion.
As mentioned before, at this point we plan to add a CI system to perform additional automated checks to the new code to be merged into master
. A CI system would detect violations to our Styleguide or broken Unit Tests. Github provides the functionality to protect master
from merges which do not meet the CI system’s criteria.
To merge a PR which has met the requirements, we simply hit the merge button on Github’s web interface. We always “create a merge commit” and never “squash and merge” nor “rebase and merge”. This further helps us keep commit history as clean and understandable as possible.
6. Changes to master should always be immediately deployed
Now our new feature has been merged into master
in our central repository, and assuming we stick to the first rule, we should deploy this new feature ASAP. Assuming master
will be immediately deployed better ensures code quality and discourages developers from trying to quickly merge buggy code.
In a nutshell (or TL;DR)
- Commits on
master
should always be deployable. - New work goes in development branches off of
master
. - Development commits should be pushed to Github often, so the rest of the team can see your code.
- PRs are used to collaborate, discuss and improve the quality of the code to be introduced to
master
. - PRs are merged into
master
via a merge commit, but only after required status checks pass. master
should be deployed to production ASAP.
That’s about it! We believe this workflow is simple yet structured enough to help developers with the on-boarding process. It can easily be extended and adapted in many ways. Furthermore, this workflow integrates wonderfully with our deployment process.
So far, we’ve simply explained the development workflow at Nexu-mx using git
and Github. But what about deployment? In part 2, I’ll give you a peek into how the Nexu-git-flow comes into play with our deployment process using Heroku, which is pure developer bliss.