Gitflow
What is Gitflow?
Gitflow is an alternative Git branching model that involves the use of feature branches and multiple primary branches.
How it works?
A develop branch is created from main
A release branch is created from develop
Feature branches are created from develop
When a feature is complete it is merged into the develop branch
When the release branch is done it is merged into develop and main
If an issue in main is detected a hotfix branch is created from main
Once the hotfix is complete it is merged to both develop and main
Pros?
Better Organization: It provides a clear structure for managing multiple branches and releases, making it easier to keep track of changes and ensure that each feature is developed in isolation.
Consistent Code Quality: By using separate branches for development and release, it helps ensure that the main branch always contains stable, production-ready code.
Easier Collaboration: Gitflow enables multiple developers to work on a project simultaneously without interfering with each other’s work, improving collaboration and productivity.
Clear Release Process: Gitflow provides a well-defined process for managing releases, making it easier to track progress and ensure that each release meets the necessary requirements.
Cons?
Complexity: Gitflow can be complex, especially for smaller teams or projects, and may require a significant investment in time and effort to implement and maintain.
Learning Curve: Gitflow can be difficult to learn and understand, particularly for developers who are new to Git or branching strategies.
Conflict prone: Gitflow can be more painful while merging conflict between branches when having multiple features developed at a same time.
Time consuming: It takes a long time to make each change, which can leave customers or users unsatisfied.
Trunk-based
What is trunk-base?
Trunk-based development is a version control management practice (or software development process) where developers merge small, frequent updates (at least once a day) to a core “trunk” (main) branch.
How scaled trunk-based development works (in a nutshell)?
You check out a new feature branch from the main branch.
You commit your code on this branch and push it to the Origin.
You open a Pull Request to main (or Merge Request as GitLab calls it).
CI verifies that your code bahaves as expected, build is not broken, quality passed, etc.
A teammate reviews your code and you adjust it according to the feedback.
You merge your branch into the main branch via the Pull Request (short PR).
Incase of hotfixes:
New hotfixes branch is created
Bugs are fixed and push to hotfixes branch
Hotfixes branch is then reviewed and merged to main
Commits are cherry picked from main to release branch
Benefits?
Short-lived feature branches
More frequent integration (actual Continuous Integration)
Fewer merge conflicts, avoid large refactoring
Can do quick release with CI/CD
Continuous (because of small changes) code-review (if basic trunk-based is used)
Minimize the need of env for testing, since we use same codebase with feature flag.
Cons?
It looks simple but harder to apply than Gitflow
Kind of harder to track for individual changes (than Gitflow) since all changes go into trunk frequently
Im considering this one to be a cons or not, solid CI/CD tools/flows are very important
Trunk-based implementation
Needs?
Short-lived feature branchs.
CI is required, that run after each commit to trunk to make sure the system is always working.
Automated testing must be effective, since full regression test cannot be performed regularly if we want to deliver to STG/PRD multiple time a day.
Feature flag (feature toggles) is non-negotiable requirement for trunk-based development.
Pull requests must be reviewed immediately, not put to later review queue.
Feature flag
For teams that use TBD and has a high release cadence with many features being developed at a same time, there will be many releases with uncompleted features.
If you’re working on an in-progress feature and you finish part of the code, you need a mechanism to tell the application to ignore that code in production. After all, your changes are going to deploy rapidly. You won’t have time to stitch the whole feature together before this code gets in front of customers.
That’s where feature flag comes in. With feature flags, you hide code for those new features behind some logic gates. Feature flags allow developers to deploy incomplete features to production without releasing them to end-users.
It’s worth noting that, if you wrap every new feature in a feature flag, then flags can quickly start filling up your codebase, creating technical debt.
Use-cases?
QA to test functionality in production and validate changes.
Product Management to manage which end users get beta program access or align releases with non-engineering business priorities.
Marketing to run A/B tests or time releases to campaigns.
Implementations?
Hard-coded constants: Slightly hacky but we’ve all created constants which could serve as default input. Then we later change the input and re-deploy. These are pretty static since they require a re-deploy.
Config files: These can come as JSON, template files, and could also be your environment config files. They’re convenient and also require a re-deploy.
Database configs: We can store application settings in a database. It is a pretty standard and convenient place to store your settings. These settings can often be updated easily in the database and often use an administration interface.
Open Source Libraries: Build specifically for feature flag management and can usually be updated on run-time. Installation and maintenance is often the biggest challenge with such libraries or even proprietary solutions.
Third-Party Service: SaaS model type of solution, is highly dynamic, and usually comes with SDKs, documentation, analytics and so on.
Best practices?
Name feature flags consistently
Don’t nest feature flags
Clean up your feature flags frequently
Release branch
Release branchs are created before the release just in time (a few days maybe), becomes a stable place, given the developers are still streaming their commits into the trunk.
The release branch “should not receive continued development work”.
The best practice for Trunk-Based Development teams is to reproduce the bug on the trunk, fix it there with a test, watch that be verified by the CI server, then cherry-pick that to the release branch and wait for a CI server focusing on the release branch to verify it there too. => we can do hotfixes on the release branch, but in some case maybe it is FORGOTTEN to be merged back to the trunk.
Release from trunk
Teams with a very high release cadence do not need (and cannot use) release branches at all. They have to release from the trunk.
Releasing from a tag on the trunk is a decent optimization for many teams, if possible. The tag could be numbered for the release (say v1.1.1), and the branch can be avoided completely. Perhaps if there is a bug in production and a branch is retroactively created from that tag, and the patch release can happen from there.
Best practices?
Develop in small batches (DevOps capabilities | Cloud Architecture Center | Google Cloud )Keeping commits and branches small allows for a more rapid tempo of merges and deployments, so we have short-lived feature branchs, that last no longer than 1-2 days.
Implement comprehensivy automated testingThis helps developers rapidly create commits and run them through automated tests to see if they introduce any new issues. (Short running unit and integration tests during development and code merge. Longer running, full stack, end-to-end tests are run in later pipeline phases against a full staging or production environment)
Perform synchronous code reviews
Have as least as possible active branches in the application's code repositoryWhile it can be beneficial for teams to see what work is in progress by examining active branches, its best to delete the feature branchs after merging.
Merge branches to the trunk at least once a day (suitable for us )
Reduced number of code freezes and integration phases
Build fast and execute immediatelyIn order to maintain a quick develop/release cadence, build and test execution times should be optimized. CI/CD build tools should use caching layers where appropriate to avoid expensive computations for static.
Bad practices
Cherry-pick of bug fixes from release branches to the trunk If you are fixing bugs on the release branch and merging them down to the trunk you are doing it wrong. There is a chance you might forget to merge it down, and then there is going to be a regression at the next release moment (fresh branch cut from the trunk). Then egg on face, and recriminations. Bugs should be reproduced and fixed on the trunk, and then cherry-picked to the release branch. A build should happen from that, a second confirmation that the issue has been remediated, and that deployment should go live (perhaps a point release). If you can not reproduce bugs on the trunk (truly rare), then you have permission to go ahead and reproduce it on the release branch, fix it there, and merge back.
Merge everything back from a release branch at the end of the release branch
Keeping a single-release branchYou principal mechanism to land code on that branch is the branch creation itself. After that only cherry picks for bug fixes as found. And there is no more cherry-picks from trunk to the old release branch.
Merge from one release branch to another release branch
Comparision
| Trunk-based development | Gitflow |
Simplicity of Merging Changes | O | X |
Isolate developers' work | X | O |
Short Production Cycles | O | X |
Implementing Small Changes | O | X |
Comments