Git has become the de facto industry standard for version control systems in software development.
You should first read my article about what Git is
and how to get started.
Have you read it? Excellent, let's get going!
Like it or not, this tool created by Linus Tovalds is not going to retire. So, it makes sense to talk about how distributed teams work with Git and what branching strategy they should choose for this.
This is not an inconsequential question. When assembling a new development team that has not worked together previously, the branching strategy is often one of the first things to decide.
And some people will be foaming at the mouth to prove that one strategy is better than another. So, I want to convey to you some general information about them.
Are branching strategies necessary?
They are indeed necessary. Very necessary. Because if the team doesn't agree on something, then each team member will do what he or she wants:
- working in whatever branch
- merging into arbitrary other branches
- deleting some branches
- creating new ones
- and so each team member will act in an unmanaged flow.
That's why we have three strategies to consider below. Let's go!
This branching strategy, oddly enough, is preferred on GitHub :) It comes with a set of rules
- Code in the master branch must not be broken. It should be ready to be deployed at any time. That is, you must not put code there that will prevent you from building the project and deploying it to the server.
- When you plan to work on new functionality, you need to create a new feature branch based on the master branch and give it a meaningful name. Commit your code locally and regularly push your changes to the same branch in the remote repository.
- Open a pull request (you can read about pull requests here) when you think the work is ready and can be merged into the master branch (or if you are unsure, but want to get feedback on the work done).
- After the new feature in the pull request is approved, it can be merged into the master branch.
- When the changes are merged into the master branch, they should be deployed to the server immediately.
According to GitHub Flow, before you start working on something new, be it a fix or a new feature, you need to create a new branch based on master and give it a suitable name.
Next, work on the implementation begins. You should constantly submit commits to the remote server with the same name. When you conclude that everything is ready, you need to create a pull request to the master branch. Then at least one, or better yet, two people should look at this code before clicking "Approve". Usually, the project's team lead and a second person should definitely take a look. Then you can complete the pull request.
GitHub Flow is also known for driving continuous delivery (CD)
in projects. This is because when changes go into the master branch, they should be deployed to the server immediately.
The previous strategy (GitHub Flow) is not very complicated at its core. There are two types of branches: master and feature branches.
But GitFlow is more serious. At least, the picture above should make that clear :)
So how does this strategy work?
In general, GitFlow consists of two persistent branches and several types of temporary branches. In the context of GitHub Flow, the master branch is persistent and the others are temporary.
- master: Nobody should touch or push anything to this branch. In this strategy, master represents the latest stable version, which is used in production (that is, on a real server)
- development: The development branch. It could be unstable.
Development happens using three auxiliary temporary branches
- Feature branches — for developing new functionality.
- Release branches — for preparing for the release of a new version of the project.
- Hotfix branches — for quickly fixing a bug found by real users on a real server.
Feature branches are created by developers for new functionality. They should always be created based on the development branch.
After completing work on the new functionality, you need to create a pull request to the development branch.
Clearly, large teams can have more than one feature branch at a time. Take another look at the picture at the beginning of the description of the GitFlow strategy.
When the required set of new features is ready in the development branch, you can prepare for the release of a new version of the product. A release branch, which is created based on the development branch, will help us with this.
When working with the release branch, you need to find and fix all bugs.
Any new changes that are required to stabilize the release branch must also be merged back into the development branch. This is done in order to stabilize the development branch as well.
When testers say that the branch is stable enough for a new release, it is merged into the master branch.
Later a tag, which is assigned a version number, is created for this commit.
To see an example, look at the picture at the beginning of the strategy. There you will see Tag 1.0
— this is just a tag that indicates version 1.0 of the project. And finally, we have the hotfix branch.
Hotfix branches are also meant for releasing a new version to the master branch. The only difference is that those releases are not planned.
There are situations when bugs get into the released version and are discovered in the production environment. Take iOS: as soon as a new version is released, you immediately get a bunch of updates with fixes for bugs that were found after the release. Accordingly, we need to quickly fix a bug and release a new version.
In our picture, this corresponds to version 1.0.1.
The idea is that work on new functionality doesn't have to stop when it is necessary to fix a bug on a real server (or as we say, "in prod" or "in production").
The hotfix branch should be created from the master branch, since it represents what is currently running in production. As soon as the bug fix is ready, it is merged into master, and a new tag is created.
Just like prepping a release branch, a hotfix branch should also merge its fix back into the development branch.
In the forking workflow, development involves two repositories:
- The original repository, into which all changes will be merged.
- A fork repository. This is a copy of the original repository, owned by another developer who wants to make changes to the original.
Sounds a bit odd so far, right?
Anyone who has already encountered open-source development is already familiar with this approach. This strategy gives the following advantage: development can happen in a fork repository without granting permissions for joint development in the original branch.
Naturally, the owner of the original repository has the right to reject the proposed changes. Or to accept and merge them.
This is convenient for both the original repository's owner and the developer who wants to help create the product.
For example, you can suggest changes to the Linux kernel
. If Linus decides they make sense, the changes will be added (!!!).
An example of the forking workflow
The forking workflow is applied on GitHub when there is a library that you want to use. It has a bug that prevents you from using it fully.
Suppose you dive deep enough into the problem and know the solution. Using the forking workflow, you can fix the problem without rights to work in the library's original repository.
To get started, you need to select some repository, for example, the Spring Framework
. Find and click the "Fork" button in the upper right corner:
This will take some time. Then a copy of the original repository will appear in your personal account, which will indicate that it is a fork:
Now you can work with this repository as usual, adding changes to the master branch, and when everything is ready, you can create a pull request to the original repository.
To do this, click the New pull request
Which strategy to choose
Git is a flexible and powerful tool that lets you work using a wide variety of processes and strategies. But the more choices you have, the more difficult it is to decide which strategy to choose.
It is clear that there is no single answer for everyone. Everything depends on the situation. That said, there are several guidelines that can help with this:
- It's best to choose the simplest strategy first. Move to more complex strategies only when needed.
- Consider strategies that have as few branch types as possible for developers.
- Look at the pros and cons of the various strategies, and then choose the one you need for your project.
That's all I wanted to say about branching strategies in Git. Thanks for your attention :)
Follow me on GitHub
, where I often post my creations involving different technologies and tools that I use in my work.