Version Control

Git, GitHub, and BitBucket

We use git version control software to track all changes to the Qobrix source files.  These include PHP source code, configuration files, documentation, unit tests, database schema files, and pretty much everything else that needs to be reproducible across different environments.  With git, we can easily find who changed every single line of code, when it was changed, and why.  It also helps us to resolve conflicts where several developers work on the same code.

If you haven’t yet learned git, you should do so now.  You can thank us later.  Seriously!  There are numerous tutorials, guides, videos, and courses online that you can use.  If you need a place to start, here’s a free online copy of the Git Book, which covers everything from getting started all the way to the advanced topics and internals.

Additionally to git itself, we are also using GitHub and BitBucket developer collaboration services.  We keep all our Open Source Software in public repositories on GitHub, and we use BitBucket for private repositories and projects.

Version Control Practices

Here are some of the basic version control practices that we adhere to, which are irrelevant to the git itself.  Even if we were using a different version control software, we’d still abide by these:

  • Commit is the smallest logical change.  It can modify as little as a single character, or it can span across large chunks of multiple files.  But as far as logical changes go, any given commit does only a single logical thing, such as fixes a bug, introduces a small feature, updates documentation section, refactors a piece of code, etc.  Keeping commits so simple minimizes the effort needed for the code review and testing, as well as makes them trivial to revert.
  • Reference ticket number in commit summary.  Ticket numbers come from several sources – GitHub, BitBucket, or our internal Redmine project management software.  Irrelevant of where the ticket came from, it should be referenced in the commit summary.  This will help to track the reason behind the changes in the future – as in, who requested the change, what was requested and why, who approved it, and how was involved in implementation, testing, and deployment.  For referencing Redmine tickets, please append the number in the following format – (task #1234).  This helps us to correctly link to issues in different sources.
  • Try to provide the long commit message.  Git supports both short and long commit messages.  While short commit messages may feel like a time saver, our practice has proven that it’s worth investing a few extra moments in the long commit message, explaining the reasons for the change.  A ticket reference from the previous point is useful, but tickets often contain non- or semi-technical requirements, which don’t always translate well into implementation details.  During the development and troubleshooting / debugging, it is much easier to pull the commit message from git than switch to the ticketing system and locate the ticket.
  • Clearly mark broken commits.  One should avoid committing broken code into the git repository, but sometimes it is necessary.  When there is no time to avoid a broken commit, please mark it clearly with [BROKEN] tag at the start of the commit summary.  This will save a tonne of time later, when trying to review changes or troubleshoot the issue commit-by-commit.
  • Never commit sensitive or temporary data.  Database dumps, uploaded files, cached data, temporary files, or credentials have no place in the repository.  Such data is very short-lived and non-critical to the operation of the application as a whole.  Given that git remembers everything forever, the history should not be polluted with temporary or sensitive information.

Feature Branch Workflow

Git is a very flexible version control software.  Different teams and organizations use it in many very different ways.  After trying a few approaches, we have selected the Feature Branch Workflow.

The core idea behind the Feature Branch Workflow is that all feature development should take place in a dedicated branch instead of the master branch. This encapsulation makes it easy for multiple developers to work on a particular feature without disturbing the main codebase. It also means the master branch will never contain broken code, which is a huge advantage for continuous integration environments.

In a moment, we’ll dive into a practical example.  But here are three things to remember if you want to follow our process (we do, of course, use technology that helps to prevent human error, but once in a while humans find ways around):

  1. The master branch is always stable and deployable.  The developer who breaks the master branch is responsible for fixing it, and fixing it ASAP.  Code reviewers who approved the breaking change and merged it into the master branch, are considered accessories to the crime and will share the responsibility with the primary developer of the breaking change.
  2. Never ever push or commit directly into the master branch.  All changes should be brought via a branch merge (Pull Request, Merge Request, etc) after all the automated tests completed, and the code review was performed.
  3. Never ever use git rebase .  Unless you are Linus Torvalds himself.  It will come back to bite you.

Here is a practical example session for you to follow:

# Switch to master branch and get remote updates
git checkout master && git pull
# Create new branch (descriptive name, ticket number)
git checkout -b api-docs-task-123
# Review your local changes
git diff
# Stage your changes
git add
# Review your stage changes before commit
git diff --cached
# Commit, forcing editor for long commit message
git commit
# Push branch to remote
git push origin api-docs-task-123