Simple git workflow at vaamo
Originally published on the Codecraft at Vaamo Blog
At vaamo we use git for version control of our
application and our code is hosted in a repository on
GitHub. While we discussed our git workflow heavily in the beginning, we've
settled for a very simple workflow for quite some time now.
Our workflow consists of the following rules:
- Everyone in the team is working on the
- We strive for a linear commit history on
masterwhich corresponds to the Centralized Workflow in this nice comparison of git workflows.
- Every push to
mastergets built and tested by Travis
- It's everyone's responsibility to recover from a failed build as fast as possible.
masteris always in a state that is ready for deployment.
That's it really.
In the following I'll explain how we manage to keep a linear commit history and discuss why we opted for this simple git workflow in comparison to others out there.
How do we keep a linear commit history
To keep the commit history linear every developer works on the local
branch and uses rebasing to integrate upstream changes from
origin/master. While we could use the handy
git pull --rebase command to do
just that, we typically use the
smart-pull command from git-smart. In
addition to rebasing,
smart-pull also takes care of stashing local changes in
the working directory and performs the rebase with the
-p flag which tries to
recreate merges if there are any in the rebase.
While most work is typically done directly on top of the local
developer at vaamo can create as many local branches as needed. As long as the
code is rebased onto
master before pushing to the central repository.
And this is basically all there is to it. Once code is pushed to
origin/master it is ready to be reviewed by others on the team.
Why not use [insert-your-favorite-workflow™ here]?
The centralized workflow is very simple and hasn't caused us any major problems during the last year. It may seem like we are not making use of the full potential of distributed version control, but git is still much better suited for a centralized workflow than e.g. Subversion would be.
Just a couple of examples: Since everybody has a full copy of the repository you can work on-the-go, amend commits as long as they are not pushed yet and do all kinds of operations very fast locally, like figuring out who changed what and why in a file.
One of the downsides of the centralized approach is that commits for a specific feature are not grouped together like they would be if we would use one branch per feature (see Feature Branch Workflow). This makes working together on a feature and discussing the relevant commits in isolation much easier (e.g. using a pull request).
Long running feature branches often require that the
master branch is merged
into the feature branch a couple of times until the feature is finished. If
done frequently - as you should - this can result in the dreaded merge bubble,
and you will have a hard time sorting out when and with what possible merge
conflict resolution a given commit was merged into
It turns out that we don't need that complexity yet. Our features are usually
divided into managable chunks and are normally only worked on by one developer.
Commits are pushed to
master frequently before the task is finished and once
it's done the developer collects the relevant commits (typically five commits
or less) on the relevant Trello card for review.
The first couple of commits for a feature contain code that is not yet on any
active execution path. Only the very last commits contains the code that
activates the feature (e.g. the user facing change in the UI or the updated
dependency injection configuration). In addition if we really have a feature
that should not yet be accessible in production for all users we still
integrate it into
master but put it behind a Feature Toggles
The last workflow that I want to quickly touch on is called Gitflow. It
combines the idea of feature branches with release management. The
what is currently in production while all ongoing development is integrated on
dev branch. A release consists of merging the
dev branch into
master. Hotfixes are possible by branching off of
master creating a
hotfixbranch and then merging the
hotfix branch both into
While this workflow is very useful when the code on
master is automatically
deployed into production, we could achieve basically the same by using tags on
master branch as triggers for a deployment.
Exceptions to the rule: When do we branch?
All that said, we are not religious about it. We still push branches from time
to time when we prototype new designs, feel like something is not quite ready
to be deployed or we wrote a piece of code that we really want to get reviewed
before merging into
master. But these are few and far between and we try to
integrate them as soon as possible
Famous last words
Commiting directly on the
master branch has worked quite nicely at vaamo for
the last year with a team of around five developers. It certainly requires a
high amount of trust in every developer and in the tests we are writing. It is
probably not the right workflow for open-source projects and as we grow we
might ourselves realize that it doesn't scale for us. What we will do at that
point, we don't know yet, but we'll figure it out once we're there.
As for the famous last words: "I'll just do
git push --force origin master,