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 is 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 must be hyphenated:

      feature/list-job-positions
      bug/user-reset-password
      chore/setup-segment
    
  • 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
  • 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. If you’re using the word “and”, then this probably is a good indicator that you might need to split it up in to a separate commit
  • Include the User Story ID between brackets [ ] at the beginning of each commit message:

      [<User Story ID>] Commit message
    

This serves two main purposes:

  1. Traceability of each commit which is very useful when rebasing, cherry-picking and merging
  2. Integration with our project management tool as commits will be displayed in the user story card
  • Write meaningful commit messages. Think that there is a high chance that you or someone else will be reading this commit message a few years from now. What would you like to communicate to your future self or developer about?

      [<User Story ID>] Implement change because ...
      [<User Story ID>] Fix the error triggered by ... in the following situation ...
      [<User Story ID>] Setup this chore so that ...
    

Everyone has their own preferred way of styling their commit messages, but as a team we need to agree on one convention only. This will lead to improved readability and clear expectations:

  • Capitalization, as we should read the commit message as a sentence

      [<User Story ID>] Add capitalized commit message
    
  • No limit to the length of maximum allowed characters, as we should describe our commit messages as detailed as possible for a better understanding

  • Start your commit message with a verb, so there’s a clear expectation of what action has been taken. This must be specified in the present tense

      [<User Story ID>] Remove ...
      [<User Story ID>] Fix ...
    
  • Periods are only acceptable when our commit messages span over multiple sentences

  • Colons are verbose and break the sentence principle, so don’t use these

  • Commits of incomplete features must be appended with the suffix wip at the end of the commit message

      [<User Story ID>] Commit message wip
    

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
      - As a user I can view the list of job positions
    
    • Mark bug fixes with the prefix Fix:
      - Fix: Login with LinkedIn
    
    • Mark bug fixes with the prefix chore:
      - 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.