One question that every team faces when moving to Git is what development workflow to use. Since every team is different and has different requirements, there is no one-workflow-fits-all approach. However, there is one rule all teams should follow when looking for a new workflow to adopt: Keep it simple. Doing so will reduce the number of mistakes people can make, and will help with adoption.
On the Stash team, we’ve adopted one of the simplest Git workflows possible. And since so many of you have asked, we’ve decided to share our workflow in the hopes that it will help you and your team adopt Git.
Every significant piece of work on the Stash team is associated with a JIRA issue. This makes it easy to track why a change was made, and when it was shipped.
For every new task, we create a branch, named using the issue key and a short description. By using the new integrated development flow found in JIRA and Stash, a developer can just click the create branch link in the JIRA view issue page.
Or, devs can create branches manually it by running the following in the console:
[cc lang=’dos’ ]$ git checkout -b STASH-22-my-task-name[/cc]
This shorthand automatically creates and switches to the new branch, so coding can start.
When thinking about branches, people generally imagine a fork of the code that lives for weeks or month, and is a nightmare to merge when ready. That’s not how you should think of branches when working with Git.
Think of them as a tool for your daily workflow. Remember, they’re easy to create and easy to merge. Branches can be as short lived as a few minutes, but generally live for a few days until the work on the specific issue or feature has been completed.
If work on a branch goes on for a longer period of time, the branch is frequently updated with changes from master to avoid a large number of conflicts once it’s is ready to be merged (Bamboo even has the option to do this for us automatically). Stay tuned for an upcoming article on the different schools of thought regarding how to keep your feature branches up to date, and whether to use merge or rebase when the development is complete.
The branch holds all code changes related to that feature, and we work on it in isolation until we are satisfied with the work. Behind the scenes, Bamboo is building and testing our branches every time we push commits to the repo. Once we have something presentable, we create a pull request from our branch back into the main development branch, typically master. A pull request is like saying. “Hey, I’ve got some changes here that I would like to merge. Can someone take a look at it?”.
We pick at least two reviewers and ask them to take a look at the pull request. To ensure reviewers have all the information they need, the pull request description should be clear about what has changed. Stash generates a pull request’s description based on the commits that are part of the pull request. This means that if your commit messages are well crafted, you’ll save time during pull request creation, and make life easier for your reviewers. In addition to the description, reviewers can also view the original requirements from the associated JIRA issues and see if the changes pass the automated builds. It’s really handy to have all this information at your fingertips when reviewing a pull request.
Pull requests are all about the discussion – general comments around the intent of the pull request, or comments on the code changes. This discussion can involve developers, QA, designers, and even product managers. If a suggestion is made to improve the code, the author can simply implement the suggestions, commit the changes, and push to the branch to automatically update the pull request. All reviewers are of course notified of the changes, and can go back to review them.
Once the reviewers are happy with the changes, they can approve the pull request. Remember that we require at least two reviewers, because we decided as a team to require at least two approvals. Once two people have approved the changes, they are ready to merge. That’s typically done by the author, or the second person to approve the changes by simply clicking the merge button in Stash. That’s it!
Single repository vs. forks
As you can tell, we are using branches on a single server – not forks – on our team. Forks are essential for an open-source workflow, where only a small number of individuals has write access to the core repository. However, in a corporate environment, everyone on the team generally has full access to the repository. Working with branches is also faster and easier than working with forks, since you don’t have to deal with multiple remotes. In the end, the workflow that’s described here can be achieved by using both branches on a single repository or forks. Our latest webinar on Git workflows has a section dedicated to pros and cons of single repository versus forks, and if you’re wondering if forks have ever a place in the enterprise I recommend that you check this article out.
For those that want an overview at a glance, here are more details on the branching model used by the Stash team at Atlassian:
- The main branch, master, is kept fairly stable – at a level comparable with alpha or even release candidate (RC), but not production quality as other branching models. The stability is greatly helped by the thorough focus on continuous integration (CI), a strong automated test coverage, and extensive performance monitoring of builds.
- One branch per user story. This is the first step to leverage the branching power of Git, so the team creates a branch for each new feature that needs to be implemented. Branches are a cheap and useful way to parallelize development. Embrace them!
- One branch per bug fix. Same concept as above: The team also creates a branch for every bug fix that needs to be applied.
- Bug fixes are merged back to the release branch where they were found, and automatically merged upwards with automated merges.
- Pull requests are created when features are close to completion with a minimum of two reviewers and build information attached.
- The team maintains long-running release branches for long-term support of the versions of Stash installed by our customers.
Long-running release branches for long-term support
What are the main long-running branches in this model?
- We have a master branch – which in Subversion (SVN) terms you would call trunk – that is stable-ish. It is in a alpha/RC state.
- We have stable release branches for each product release we have to ship updates to.
Commits always are merged upwards from older to newer branches. If a fix needs to be applied to stable branch 2.2 for example, a bug fix branch is created off the stable branch. First it gets merged back to that branch, and then that branch is merged upwards towards master. These chains of merges can be several branches long, but this operation is almost completely automated.
Wrapping it up
In conclusion let me reinforce the notion that our workflow at a high level is actually quite simple. It can be described compactly in three easy steps:
- New features and bug fixes are developed on branches
- Two team members review the changes
- The changes are merged back into the main development branch
Of course every team works differently, and this might not work for everyone. But it’s easy to adapt this workflow and include your additional requirements.
Anyone can be good, but awesome takes teamwork.
Find tools to help your team work better together in our Git Essentials solution.