Git, like other version control systems, is a powerful tool. It takes a fair amount to master. However, even once you remember the commands and know how it operates from a technical perspective, figuring out a good way to use it to organize a project remains a challenge. How do you use it effectively within a team and use it as an effective tool to do release management for your product?
At Cloud9 IDE, we have gone through several iterations to find a good solution to this problem. At the same time we changed our development process as well. Before, we had Scrum-style sprints that lasted a couple of weeks. However, inspired by the guys at GitHub, recently we have moved to a more asynchronous process where features are released whenever they are ready — with daily releases, sometimes.
Within the company, we rely heavily on Git and GitHub. All of our code is on our github account. While we used git-flow before, it did not completely fit our release cycle. Therefore, we adopted what can be referred to as “GitHub Flow”.
Inspired by GitHub’s process, here are the two golden rules of software development at Cloud9 IDE:
Rule #1: Never commit directly to the “master” branch.
Never. Well, unless you have to fix this one litt… No! Never. Commit. To. Master.
Why? The “master” branch has to be stable and ready to be released at all times. That means that all features and fixes merged into this branch have to be done.
And when we say “done”, we have something very specific in mind, which brings us to golden rule number two.
Rule #2: A feature is only considered done when:
- It follows our coding standards
- It can be cleanly merged into “master” without conflicts
- It has extensive tests, and those tests succeed — both unit tests and selenium tests (if applicable)
- It has been code reviewed by at least one (senior) developer in the team
So, what workflow does this result in, in practice?
Our Development Workflow
Each developer has a local clone of the repository. When we want to start working on a new feature, we branch off the “master” branch using a branch name that describes the feature concisely. We work on this branch locally (editing using Cloud9, of course) and push the branch to the central GitHub repository from time to time. Pushing the branch to the central repository both enables other team members to watch the feature progress and to try the feature out, but also is an additional back-up mechanism of the work in progress.
Depending on the feature, the work may be developed using test-driven development or in a more ad-hoc way, where tests are written after the fact. Either way is fine, as long as there are good tests in the end.
While developing a feature, we often record a little screencast of the feature in action using either screenr or Jing to show it to other people in the team, which can then provide feedback. Ideally, the final pull request comes with a screencast as well, demonstrating the feature.
Every morning (or more often), we merge the latest changes from the “master” branch into our feature branch, to keep up with recent changes and to avoid large merging conflicts at a later time.
When the feature has been completed from a code and test perspective, it is time to issue a pull request with the “master” branch. GitHub provides a very nice UI for this these days. In the pull request we use the @username notation in the description field to assign the review to one or more people, who will receive an e-mail about the new pull request.
The pull request is a very convenient tool to do code reviews. It has a “Diff” view which shows all the changes of the pull request compared to the current “master” branch — so there is no need to look through each commit individually. Each line of the code can be commented on to give suggestions for improvement or ask clarification questions.
All comments on the pull requests are neatly presented in the pull request’s main view.
Then, when everybody is happy about the feature, the “Merge” button is pushed and the new feature lands in the master branch. Ready to be released to the public.
Planned Improvements to our Process
We are looking to improve our process in two more ways in the very near future:
- Continuous integration, which is already up and running for our ACE project. A continuous integration service automatically builds and runs all tests after every push to the main repository and e-mails people when it breaks.
- Automated feature roll-outs and roll-outs to groups of users. Currently releasing a new version is a manual process. We need to automate it. In addition, we will soon have the infrastructure to test out new features with specific groups of users, like Google does — to see how it works, before rolling it out to everybody.
Sounds like your way of working? Consider joining us!