Now that you learned how to perform good commits, it's time to fly higher and think about workflows. Git is a tool for versioning, but as with other powerful tools, like knives, you can cut tasty sashimi or relieve yourself of some fingers.
The things that separate a great repository from a junkyard are the way you manage releases, the way you react when there is a bug to fix in a particular version of your software, and the way you act when you have to make users beta-test the incoming features.
These kinds of actions belong to ordinary administration for a modern software project. However, very often, I still see teams get out of breath because of the poor versioning workflows.
In this second part of the chapter, we will take a quick look at some of the common workflows alongside the Git versioning system.
As we used to do in other VCSes, such as Subversion and so on, even in Git, it is common to adopt a centralized way of work. If you work in a team, it is often necessary to share repositories with others, so a common point of contact becomes indispensable.
We can assume that if you are not alone in your office, you would adopt one of the variations of this workflow. As we know, we can get all the computers of our co-workers as remote, in a sort of peer-to-peer configuration. However, you usually don't do this, because it becomes too difficult to keep every branch in every remote in sync.
At this point, you probably will choose a feature branch approach, where every single developer works on their branch. When the work is done, the feature
branch is ready to be merged with the master
branch. You will probably have to merge back from the master
branch first because one of your other colleagues has merged a feature
branch after you started yours, but after that you basically have finished.
The GitFlow workflow comes from the mind of Vincent Driessen, a passionate software developer from the Netherlands. You can find his original blog post at http://nvie.com/posts/a-successful-git-branching-model.
His workflow has gained success over the years, at the point that many other developers (including me), teams and companies started to use it. Atlassian, a well-known company that offers Git related services such as Stash or Bitbucket, integrates the GitFlow directly in its GUI tool, the SourceTree.
Even the GitFlow workflow is a centralized one, and it is well described by this figure:
This workflow is based on the use of some main branches. What makes these branches special is nothing other than the significance we attribute to them. These are not special branches with special characteristics in Git, but we can certainly use them for different purposes.
In GitFlow, the master
branch represents the final stage. Merging your work in it is equal to making a new release of your software. You usually don't start new branches from the master
branch. You do it only if there is a severe bug you have to fix instantly, even if that bug has been found and fixed in another evolving branch. This way to operate makes you superfast when you have to react to a painful situation. Other than this, the master
branch is where you tag your release.
Hotfixes branches are branches derived only from the master
branch, as we said earlier. Once you have fixed a bug, you merge the hotfix
branch onto master
so that you get a new release to ship. If the bug has not been resolved anywhere else in your repository, the strategy would be to merge the hotfix
branch even into the develop
branch. After that, you can delete the hotfix
branch, as it has hit the mark.
In Git, there is a trick to group similar branches: you have to name them using a common prefix followed by a slash /
. For the hotfix
branches, I recommend the hotfix/<branchName>
prefix (for example hotfix/LoginBug
of hotfix/#123
for those who are using bug-tracking systems, where #123
is the bug ID).
These branches are usually not pushed to remote. You push them only if you need the help of other team members.
The develop
branch is a sort of beta software branch. When you start to implement a new feature, you have to create a new branch starting from the develop
branch. You will continue to work in that branch until you complete your task.
After the task is completed, you can merge back to the develop
branch and delete your feature
branch. Just like hotfix
branches, these are only temporary branches.
Like the master
branch, the develop
branch is a never-ending branch. You will never close nor delete it.
This branch is pushed and shared to a remote Git repository.
At some point, you need to wrap up the next release, including some of the features you implemented in the last few weeks. To prepare an incoming release, you have to branch from develop
, assigning at the branch a name composed of the release
prefix. This will be followed by the numeric form of your choice for your release
branch (for example release/1.0
).
Pay attention. At this stage, no more new features are allowed! You cannot merge develop
onto the release
branch. You can only create new branches from that branch for bug fixing. The purpose of this intermediate branch is to give the software to beta testers, allowing them to try it and send you feedback and bug tickets.
If you have fixed some bugs onto the release
branch, the only thing to remember is to merge them even into the develop
branch, just to avoid the loss of the bug fix. The release
branch will not be merged back to develop
.
You can keep this branch throughout your life, until you decide that the software is both mature and tested sufficiently to go in production. At this point, you merge the release
branch onto the master
branch, making, in fact, a new release.
After the merge to master
, you can make a choice. You could keep the release branch open, if you need to keep alive different releases; otherwise, you can delete it. Personally, I always delete the release
branch (as Vincent suggests), because I generally do frequent, small, and incremental releases (so, I rarely need to fix an already shipped release). As you certainly remember, you can open a brand new branch from a commit (a tagged one in this case) whenever you want. So, at most, I will open it from that point only when necessary.
This branch is pushed and shared to a common remote repository.
When you have to start the implementation of a new feature, you have to create a new branch from the develop
branch. Feature branches start with the feature/
prefix (for example, feature/NewAuthenitcation
or feature/#987
if you use some feature- tracking software, as #987
is the feature ID).
You will work on the feature release until you finish your work. I suggest that you frequently merge back from develop
. In the case of concurrent modifications to the same files, you will resolve conflicts faster if you resolve them earlier. Then, it is easier to resolve one or two conflicts a time than dozens at the end of the feature work.
Once your work is done, you merge the feature onto develop
and you are done. You can now delete the feature
branch.
Feature branches are mainly private branches. However, you could push them to the remote repository if you have to collaborate on it with some other team mates.
I recommend that you take a look at this workflow, as I can assure you that there was never a situation that I failed to solve using this workflow.
You can find a deeper explanation with the ready-to-use Git command on Vincent Driessen's blog. You can even use GitFlow commands Vincent made to customize his Git experience. Check them out on his GitHub account at https://github.com/nvie/gitflow.
The previously described GitFlow has tons of followers, but it is always a matter of taste. Someone else found it too complex and rigid for their situation. In fact, there are other ways to manage software repositories that have gained consensus during the last few years.
One of these is the workflow used at GitHub for internal projects and repositories. This workflow takes the name of GitHub flow. It was first described by the well-known Scott Chacon, former GitHubber and ProGit book author, on his blog at http://scottchacon.com/2011/08/31/github-flow.html.
This workflow, compared to GitFlow, is better tailored for frequent releases. When I say frequent, I say very frequently, even twice a day. Obviously, this kind of flow works better on web projects, because to deploy it, you have to only put the new release on the production server. If you develop desktop solutions, you need a perfect oiled update mechanism to do the same.
GitHub software basically doesn't have releases, because they deploy to production regularly, even more than once a day. This is possible due to a robust Continuous Delivery structure, which is not so easy to obtain. It deserves some effort.
The GitHub flow is based on these simple rules.
Just like GitFlow, even in GitHub flow, deployment is done from the master
branch. This is the only main branch in this flow. In GitFlow, there are not hotfix
, develop
, or other particular branches. Bug fixes, new implementation, and so on are constantly merged onto the master
branch.
Other than this, code in the master
branch is always in a deployable state. When you fix or add something new in a branch and then merge it onto the master
branch, you don't deploy automatically, but you can assume your changes will be up and running in a matter of hours.
Branching and merging constantly to the master
branch, which is the production-ready branch, can be dangerous. You can easily introduce regressions or bugs, as no one other than you can assure you have done a good job. This problem is avoided by a social contract commonly adopted by GitHub developers. In this contract, you promise to test your code before merging it to the master
branch, assuring that all automated tests have been successfully completed.
In GitFlow, you always branch from the master
branch. So, it's easy to get a forest of branches to look at when you have to pull one. To better identify them, in GitHub flow, you have to use descriptive names to get meaningful topic branches. Even here, it is a matter of good manners. If you start to create branches named stuff-to-do
, you would probably fail in adopting this flow. Some examples are new-user-creation
, most-starred-repositories
, and so on (note the use of dashes). Using a common way to define topics, you will easily find branches you are interested in, looking for topics' keywords.
Another great difference between GitHub flow and GitFlow is that in GitHub flow, you push feature branches to the remote regularly, even if you are the only developer involved and interested in it. This is done even for backup purposes. Even if I already exposed my opinion in merit, I can't say this is a bad thing.
A thing I appreciate about GitFlow is that this habit of pushing every branch to the remote gives you the ability to see, with a simple git fetch
command, all the branches currently active. Due to this, you can see all the work in progress, even that of your team mates.
In Chapter 3, Git Fundamentals – Working Remotely, we talked about GitHub and made a quick try with pull requests. We have seen that basically they are for contributing. You fork someone else's repository, create a new branch, make some modifications, and then ask for a pull request from the original author.
In GitHub flow, you use pull requests massively. You can even ask another developer of your team to have a look at your work and help you, give you a hint, or review the work done. At this point, you can start a discussion about using the GitHub pull request to chat and involve other people, putting their usernames in CC. In addition, the pull request feature lets you comment even a single line of code in a different view, letting users involved proficiently discuss the work under revision.
You can now understand that the pull requested branch stage we saw earlier becomes a sort of review stage. Here, other users can take a look at the code and even simply leave a positive comment, just a +1 to make other users know that they are confident about the job, and they approve its merge into master
.
After this step, when the CI server says that the branch still passes all the automated tests, you are ready to merge the branch in master
.
At this stage, you merge your branch into master
, and the work is done. The deployment is not instantly fired, but at GitHub, they have a very straight and robust deploy procedure. They deploy big branches with 50 commits, but also branches with a single commit and a single line of code change, because deployment is very quick and cheap for them.
This is the reason why they can afford such a simple branching strategy, where you put on the master
branch, and then you deploy, without the need to pass through the develop
or release
stage branch, like in GitFlow.
I consider this flow very responsive and effective for web-based projects, where basically you deploy to production without focusing too much on versions of your software. Using only the master
branch to derive and integrate branches is faster than light. However, this strategy could be applied only if you have these prerequisites:
This is a big picture of this flow. For more details, I recommend that you visit the GitHub related page at https://guides.github.com/introduction/flow/index.html.
Obviously, there are many other workflows. I will spend just few words on the one that (fortunately) convinced Linus Torvalds to realize the Git VCS.
The Linux kernel uses a workflow that refers to the traditional way in which Linus Torvalds has driven its evolution during these years. It is based on a military-like hierarchy.
Simple kernel developers work on their personal branches, rebasing the master
branch in the reference repository. Then they push their branches to the lieutenant developer's master
branch. Lieutenants are developers who Linus assigned to particular topics and areas of the kernel because of their experience. When a lieutenants have done their work, they push it to the benevolent dictator master
branch (Linus branch). Then, if things are OK (it is not simple to cheat him), Linus would push his master
branch to the blessed repository, the one that developers use to rebase from, before starting their work.