Introduction
When we start to work with git, it's hard to understand how do you should work with branches correctly to avoid conflicts, have a nice and organized history and a project that it's easy to deploy and rollback if necessary.
In this article, I'll explain the best gitflow that exists and why each of these parts are there.
The core concepts
To worik with gitflow we must understand 2 core concepts: branches and merging strategies.
There are 3 types of branches:
- The main "branches"
- The feature branches
- The task branches
And 3 types of merge strategies:
- Merge
- Squash
- Rebase
Branches
You can think of Git as a Tree, it has it's trunk and it's branches.
They are "copies" of the main system, so you can do all the changes that you want without altering the main content, so you can revert these changes, apply them other branches, and do a lot of cool stuff with it.
The main "branches"
I recommend to have only one main branch on your repository, and not a develop
and production
branches. Why? Because branches are BRANCHES! Ramifications of something that can (but shouldn't) follow different paths of the original, and not something to save a persistent state and never change again.
I 100% against using branches for production
or release versions (branches like v1.0.0
and similar), we have many other ways (correct ways!) to do it and we should avoid this workaround.
Git has support for release tags, which are pretty good to name your releases and know when something goes to production. They are kinda editable too, in case you need it, but it's always best to have immutable releases and release a fix if needed.
You also can use Releases in GitHub, that are very helpful to have a zip file with all your code, and also has lot's of integrations and automations.
So, to summarize:
- I recommend the use of ONE main branch, and for being a old timer, I call it
master
, but you can call itmain
if you prefer. - In this article, I'll be using GitHub Releases, but if you use other remote repository, you can understand it as git tags.
The feature branches
When we work in a True Agile environment, we have features planned that must be implemented, like a feature to allow the user to create an account, in Scrum, they call these things "User Stories".
At the beginning of every cycle (or "sprint" if you use Scrum), it's created a new branch from the main branch with the pattern:
// Pattern
feature/<ID in lowercase>/<description in lowercase>
// Example
feature/ant-1/create-account
This branch is created from the main branch and will group all the changes of this feature. After everything that the feature needs is merged and tested, the branch will be merged back to the main branch.
The task branches
Task branches are sort-lived branches that apply specific changes needed to create that feature, like small pieces of that feature.
They can be understood as "Jira Tickets" or "Issues".
They are created from the FEATURE branches and merged on them.
// Pattern
task/<ID in lowercase>/<description in lowercase>
// Example
task/ant-2/password-adapter
Other branches and their prefixes
As you could have noticed in the previous topics, feature and task branches have different prefixes, but follow the same patterns.
Every other branch that isn't the main branch will have some kind of prefix, and the existent prefixes are:
# Same level as feature branches
hotfix
feature
refact
# Same level as task branches
task
fix
refact
chore
cicd
You already know feature
and task
, but let know the other ones.
hotfix
: Created to fix something urgently, usually things broken from the previous release that needs to be fixed in order to publish a new release because rollback is not an option.
refact
: Changing a feature that already exists in the system, without affecting its behavior. The refact
branch in the same level as a feature
branch is used in order to refact a big portion of your system, a core feature, like user account creation, and not to refact a for loop.
fix
: A bugfix that will follow the right flow of development, will be tested before merged, and will be merged with all the other things of the feature (what may take a while).
refact
: The refact
branch in the same level as a task
branch is used in order to refact small portions of your code, affecting its behavior or not. These branches must be part of a feature, and can change things like your internal API to send messages to topics, improve the performance of a for loop, etc.
chore
: Update in a comment, a development script, README, things that doesn't affect the code.
cicd
: Updates in the pipelines, configurations for deploying.
Merge strategies
Here I'll give a quick resume about the topic, but you can learn more in the official documentation.
The thing that we will focus on is: squashing before merging:
- Every task should have 1 commit when merging to a feature, so you MUST ALWAYS squash your commits before merging.
- Every feature should have 1 commit when merging to the main branch, so you MUST ALWAYS squash your commits before merging.
GitHub automatically squashes your commits for you if you configure it right:
But you can also do it with the CLI, see the docs.
Extra tips
Commit message pattern
I use A simplified version of Clean Arch for my projects, from this i get the layers, and the pattern that i use for the commit messages is:
// Pattern
<prefix>(<scope in lowercase>): <short description in lowercase>
// Examples
task(adapters): add foo adapter
fix(usecases): fix user creation
chore(docs): add details to readme
cicd(deploy): change deploy method
hotfix
, feature
, refact
, task
, fix
use the layers as the scope.
On the frontend web, you can use the names of the folders under src
as the scope.
chore
can use docs
, comments
or naming
as the scope.
cicd
can use deploy
, review
or tests
as the scope.
Commits that fix PR comments doesn't need a special pattern since they will be squashed, you can use just fix pr comments
or some message that you can kinda understand.
Small teams
If you are working in a small team, there's no need to have feature branches, you can work directly with task branches, this will decrease the complexity of your system.
Advantages of this GitFlow
A nice and clean commit history
In your main branch you will be able to see all the features that your software have and the evolution of it.
In your PR history, you will be able to see all the feature branches (this history is even better if you use the right labels to filter your PRs!), and all the branches and changes related to them.
Standard
Everyone works in the same way because all of you have a standard to follow. It's easier to recognize patterns and understand the way that all teams work with git.
GitFlow using the best gitconfig
When using the best gitconfig, it's very, very easy to work with git:
# At the start of the cycle
git ckm
git cb feature/ant-1/create-account
# To start a task
git ck feature/ant-1/create-account
git pl
git cb task/ant-2/password-adapter
# When task finished
git acips task(adapters): add password adapter
# If you need to do any adjusts on your commit (even after the PR is created) you can run
git acaps task(adapters): add password adapter
# If there's comments on your PR and you need to fix them, create anoter commit
git acips fix pr comments
# Create the PR and it's done!
# To create another task, just start from "To start a task"
Conclusion
Thanks for reading, I think that this article has everything that you need to know to be able to work with Git. If you have any thoughts, please feel free to share them with us in the comments! 😄
Top comments (0)