There are a lot of people explaining GitFlow in different blog posts and videos. I could not find one that, using the correct arguments, explained what it is good for. These are my personal opinions and you don't have to agree =)
GitFlow is really the simplest thing. Let's divide the people working with a project into 2 different roles, developers and configuration manager(s), and look at what they do.
GitFlow as a developer
As a developer you have 2 kinds of branches.
- develop Integration branch. Refers to the next release.
- feature/X Feature branch where feature X is developed.
You may have feature branches that branch out of other feature branches. In order to, easily, collaborate with other developers on a larger feature. You may call that large feature branch, integration branch.
- You should always merge code to develop as fast as you can. To spread commits quick and avoid merge conflicts.
- You should regularly rebase, or merge, develop into you feature branch. To base you code on the latest features and refactorings and avoid merge conflicts.
To work on the next release. You branch out of develop, work with the feature, merge back to develop.
* (develop) Merge branch 'feature/work-with-correcting-a' into develop |\ | * (feature/work-with-correcting-a) Correcting a |/ * Merge branch 'feature/work-with-a' into develop |\ | * (feature/work-with-a) a |/ *
To work on the next-next release, or even further into the future, simply don't merge it back to develop before next-next is next. And keep in mind, it may be a good idea to merge it into develop earlier, to avoid merge conflicts, if you can do feature toggling.
As a developer, this is all there is to it! This is how developers most often prefer to work. Just look at any open source repository. Most often you fork the main repository and the master in your fork is your feature branch. But still, this is as simple as it can get and this is how developers do it!
GitFlow as a configuration manager
As a configuration manager you have 2 kinds of branches.
- master This is the what's in production.
- release-X This is what's included in release X.
As soon as it's code freeze it's time to create the first release candidate. That is done by branching out of develop into release-X. The version of develop is now set to 1.1, in Java that would mean changing the version to 1.1-SNAPSHOT while in the release branch its still 1.0-SNAPSHOT. The semantics of the versions is a side track, but I can recommend this blog post.
| * (release-1, tag: 1.0-RC-1) Releasing RC 1 | * Setting version to 1.0-RC1 * | (develop) Setting version to 1.1-SNAPSHOT |/
The whole point of the release-X branch is to provide a code freeze for the release. The developers can continue their work exactly as described above. Most Git services allows you to define permissions per branch and only configuration managers should have permission to release-X.
The release candidate, RC1, is deployed and tested and if it's all good then it's released. But there is probably something that needs to be fixed. It can be done in different ways.
With cherry-picking from develop.
This is the prettiest but it may also not be possible. Merge conflicts may hinder this. There is also a risk that the develop-branch is too far ahead making it hard to know if the fix will work once it's in the release-branch. But I feel that it gives the configuration manager the most control of the release process.
With merging a feature-branch that branches out of the release-branch.
This often my preferred choice in large teams. It gives the configuration manager control of what's included in the release. It avoids risk of merge conflicts. The tests done on that feature-branch can be trusted. It can be done with pull requests.
With direct commits to the release-branch.
This may fit a technical team where the configuration manager is also a developer. It provides a release process for the current release and enables the developer to work on the next release in develop. It lacks support for code review but you may not need that in a small project.
Here is what it may look like if cherry-picking is used.
| * Setting version to 1.0-SNAPSHOT | * (release-1, tag: 1.0-RC-2) Releasing RC 2 | * Setting version to 1.0-RC2 | * Correcting a | * Setting version to 1.0-SNAPSHOT | * (tag: 1.0-RC-1) Releasing RC 1 | * Setting version to 1.0-RC1 * | (develop) Setting version to 1.1-SNAPSHOT |/
Now if RC2 is good and should be released then that exact artifact is deployed in production.
- Released commit, release-tag, in release-1 is merged into master.
- To keep track of what is in production.
- master is merged into develop, this is important:
- To make sure any changes made in production are also in the next release.
- To allow a fast-forward of master next time you merge release-tag to master.
I've shown the two roles in GitFlow and I hope I made it obvious that its actually a very simple workflow! It will not fit all projects.
You will probably not gain from using GitFLow in a library. That is just used by other software. Where a release is just a process of packaging an artifact an making it available for other software to use. You can probably just release a new version if something needs to be fixed later, and the users of the software can just keep using an older version until things are worked out.
You will probably gain from using GitFlow if you have a code freeze. It enables a code freeze without preventing developers from working on the next release.
If you just fire releases from master, without any branching, you can easily automate that process. If you need to make a release-branch and eventually merge it back into master, and develop, you will need a more complex flow. Which is a price you may not want to pay unless you are gaining something else from the flow!