Version Control

Hero image for Version Control

We always use Git for our code version control needs. No matter how big or small the project is, Git is required at all times as it allows us to track changes, revert to previous without using ctrl-z 😨 and primarily work efficiently as a team.

Services

Github and Bitbucket are both used depending on the nature and requirements of the project. As a general rule, this how we decide which service to use:

  • Github:
    • Private repositories for native mobile applications (iOS and Android) as most Continuous Integration providers only work with Github
    • Private repositories for web projects for clients who already use Github for their organization
    • Public repositories for open source projects developed by us
  • Bitbucket private repositories for everything else

Branching

Our methodology is mostly inspired from git-flow which basically allows to separate works by branch types: feature, bug, chore and release.

  • By default, there must be 2 branches: master and development. Both branches must be created when setting up the code repository.
  • The master branch is the version in production
  • The development branch is the version currently on the staging environment
  • No one should commit directly to either the master or development branches
  • Commit history rewrites on either the master or development branch must be avoided at all costs as it could leave the project in a dire state
  • Branches names should be hyphenated e.g feature/list-job-positions or bug/user-reset-password
  • All features, bugs, chore and releases branches must be checked out locally from the development branch. By avoiding branching more than one node away from the main branch, we can easily avoid complex conflicts and rebasing which can take hours or days to solve
  • The definition of what constitutes a feature, bug or chore depends on the user story type. No code should be committed if there is not a user story for the tasks at hand
  • Releases branches are required when opening a pull request to merge code into the master branch. No code is merged directly into the master branch
  • Release branches name must contain the corresponding version number e.g. release/1.0.0

Committing code

  • Write clear and precise messages for each commit
  • Include the User Story ID between brackets at the beginning of each commit message e.g. [<User Story ID>] commit message. This serves multiple purposes: 1) traceability of each commit which is very useful when rebasing, cherry-picking and merging, and 2) integration with our project management tool as commits will be displayed in the user story card
  • Commits of incomplete features must be appended with the suffix wip at the end of the commit message e.g. [<User Story ID>] commit message wip
  • Commit regularly to avoid losing any massive amount of changes
  • Stage file changes in a meaningful way i.e. commit changes for a group of files together with a good commit message. All staged files must correspond to the same change

Tagging

Once code is merged into the master branch, we keep track of versions by using git tags.

  • Add a tag locally corresponding to the version release from the master branch. Push the local tag to the remote code repository
  • Add changelog in the commit message for the tag following this convention:
    • List changes as a bullet point list
    • Use story title for new features e.g. As a user I can view the list of job positions
    • Mark bug fixes with the prefix Fix: e.g. Fix: Login with LinkedIn
    • Mark bug fixes with the prefix chore: e.g. Chore: Set up staging environment

Releases ⛴

In order to release a new version, it is required to combine a few of the aforementioned techniques:

  • Checkout a release branch from the development branch. Naming for the branch should follow the pattern release/<version number> e.g. release/1.0.0
  • Open a pull request with the release branch as origin and the master branch as destination
  • Once the pull request is approved and / or the test suite has run successfully, merge the release branch
  • Add a git tag for the version e.g. git tag -a 1.0.0 with releases notes when entering the interactive mode
  • Push newly added tag to the remote with git push --tags

We follow Semantic Versioning for all projects; starting from 0.1.0 to 1.0.0 (or above) at the pace of one minor release per sprint.