Workflows
Gitflow Workflow
Gitflow is a structured branching model that assigns specific, rigid roles to different branches to manage complex software release cycles. It provides a robust framework that prevents experimental code from destabilizing production, ensuring a clear history and reliable deployment path. You should reach for this workflow when you are managing large projects with scheduled release cycles and a need for concurrent development across multiple versions.
The Core Branches: Master and Develop
The foundation of Gitflow relies on two long-lived branches that exist for the entire lifespan of the repository. The 'master' branch acts as the single source of truth, containing only production-ready code that is tagged with version numbers. The 'develop' branch serves as the integration branch for all new features. By separating these, you gain the ability to conduct intense integration testing on 'develop' without ever endangering the stability of 'master'. This architecture allows teams to work on upcoming features while simultaneously keeping the production environment pristine and ready for an emergency hotfix. Understanding this split is critical because it forces a discipline where you do not commit directly to master. Instead, you treat the master branch as a historic record of releases, while the develop branch acts as the active, evolving landscape where the next version of the software is systematically constructed and stabilized through constant peer review.
# Initialize the repository structure
git branch -m master
git checkout -b develop # Create the integration branch
git push -u origin master develop # Push both foundation branchesFeature Branch Lifecycle
When a developer begins work on a new requirement or improvement, they create a 'feature' branch derived specifically from the 'develop' branch. This keeps the work isolated, preventing unstable or incomplete code from interfering with other concurrent development efforts. The logic here is centered on encapsulation; by branching off develop, you ensure the feature starts with the latest integrated work. Once the feature is complete, it is merged back into develop, and the feature branch is deleted to keep the repository clean. This workflow promotes parallel development because multiple developers can work on distinct features simultaneously without merge conflicts occurring in the main integration line. If you need to reason about why this works, consider that it enforces a linear flow for feature integration, making it trivial to track when specific functionality was added or to revert a feature if the integration testing reveals a regression after the merge.
# Start a new feature from develop
git checkout develop
git checkout -b feature/login-module
# ... work, commit, work ...
git checkout develop
git merge --no-ff feature/login-module # Preserve branch history
git branch -d feature/login-module # Clean upThe Release Preparation Phase
Once the 'develop' branch has accumulated enough completed features for a new release, you create a 'release' branch. This is the stage where the focus shifts from adding new features to stabilization, bug fixing, and documentation tasks. By branching a 'release' from 'develop', you effectively freeze the feature set for this specific version. This allows the team to continue merging new features into 'develop' for the *following* release cycle, while the release branch receives only critical bug fixes. If a flaw is discovered during final manual verification or performance testing, the fix is applied here and then immediately back-merged into 'develop'. This approach is highly effective for project managers who need to maintain a predictable release schedule. It ensures that the 'develop' branch is never blocked by the final polish required for a product launch, maintaining a high velocity of development regardless of the release state.
# Start a release branch from develop
git checkout develop
git checkout -b release/v1.0.0
# ... polish, fix last-minute bugs ...
git checkout master
git merge --no-ff release/v1.0.0
git tag -a v1.0.0 -m "Release 1.0.0"Emergency Hotfixes
Hotfixes are a necessary evil when a critical bug reaches the production environment. Unlike features or releases, a 'hotfix' branch is derived directly from the 'master' branch. This is the only scenario where you deviate from the path of developing through 'develop'. The reason for branching from master is to isolate the patch so it can be deployed immediately without dragging in unfinished code currently sitting in the 'develop' branch. Once the critical bug is resolved in the hotfix branch, it is merged into both 'master' and 'develop'. This dual-merge strategy is vital because it ensures that the fix is not only applied to production but also permanently persisted in the next release. If you fail to merge back into 'develop', you risk a regression where the bug reappears in the next major update, which would be disastrous for long-term project stability.
# Create a hotfix from master
git checkout master
git checkout -b hotfix/critical-patch
# ... patch code ...
git checkout master
git merge --no-ff hotfix/critical-patch
git checkout develop
git merge --no-ff hotfix/critical-patch # Ensure develop gets the fixManaging History with --no-ff
A common point of confusion is the use of the '--no-ff' flag during merges. In Git, a fast-forward merge simply moves the branch pointer forward, which can make history look like a series of disconnected commits. By using '--no-ff', you force Git to create a merge commit, even if the fast-forward option was possible. This is essential in Gitflow because it preserves the historical record that a specific set of commits belonged to a specific feature or release. When looking at the commit graph later, you can clearly see the 'bubble' created by the merge, which identifies the lifespan of the branch. This creates a much more readable and traceable history. If you are ever debugging a production issue, having these explicit merge points allows you to pinpoint exactly when a feature was introduced or when a release was finalized, which is invaluable for technical audits and troubleshooting.
# Force a merge commit for clarity
git checkout develop
git merge --no-ff feature/user-profile
# The log will now show a clear merge node
git log --graph --onelineKey points
- The master branch should only contain production-ready, tagged releases.
- The develop branch serves as the integration point for all upcoming features.
- Feature branches must be created from develop to maintain isolation.
- Release branches allow for stabilization without stopping development on new features.
- Hotfixes are branched from master to provide an immediate production patch.
- Always merge hotfixes into both master and develop to prevent regressions.
- Using --no-ff preserves the history and context of merge operations.
- Branch naming conventions help teams identify the purpose of every active branch.
Common mistakes
- Mistake: Committing directly to the master or main branch. Why it's wrong: Gitflow dictates that main is reserved for production-ready code. Fix: Always create feature branches from develop and merge them back into develop first.
- Mistake: Failing to pull the latest changes before starting a new feature. Why it's wrong: This leads to significant merge conflicts later in the process. Fix: Always ensure your local develop branch is up to date with the remote before branching.
- Mistake: Including unfinished or 'dirty' code in a release branch. Why it's wrong: The release branch should only be for final polishing and metadata updates. Fix: Complete all feature development in feature branches before initiating a release.
- Mistake: Merging hotfixes directly into the develop branch. Why it's wrong: While it eventually reaches develop, the primary goal of a hotfix is to address a production issue. Fix: Merge hotfixes into both main and develop to ensure the fix is deployed and the development cycle is updated.
- Mistake: Treating hotfix branches as feature branches. Why it's wrong: Hotfix branches must be branched off of main, not develop. Fix: Use the standard hotfix naming convention and branch directly from main to target immediate production bugs.
Interview questions
What is the primary purpose of the Gitflow workflow in a software project?
The primary purpose of the Gitflow workflow is to provide a robust, structured framework for managing complex release cycles. It achieves this by defining specific roles for different branches, such as master, develop, feature, release, and hotfix branches. This separation ensures that the main codebase remains stable and deployable at all times, while allowing developers to work on new features and bug fixes in isolated environments without interfering with the production-ready code.
What are the specific roles of the 'master' and 'develop' branches in Gitflow?
In Gitflow, the 'master' branch is reserved exclusively for production-ready code. Every commit on 'master' should ideally be a tagged release version. Conversely, the 'develop' branch serves as the integration branch for all ongoing feature development. Developers merge their completed features into 'develop' to aggregate changes. By separating these two, Gitflow ensures that the 'master' branch history remains clean and strictly reflects the state of the production environment, while 'develop' acts as the historical record of project progress.
How does a developer integrate a new feature into the codebase using Gitflow?
To integrate a new feature, a developer starts by creating a 'feature' branch off the 'develop' branch using the command 'git checkout -b feature/my-feature develop'. Once the development work is finished, the developer merges this feature branch back into 'develop' using 'git checkout develop' followed by 'git merge --no-ff feature/my-feature'. The '--no-ff' flag is critical because it creates a merge commit even if the merge could be resolved as a fast-forward, ensuring that the history clearly shows the existence of a feature branch.
Compare the Gitflow workflow to the GitHub Flow approach; when would you choose one over the other?
Gitflow is a rigid, multi-branch workflow ideal for projects with scheduled release cycles and strict versioning, whereas GitHub Flow is a lightweight, branch-based workflow centered around the 'master' branch and pull requests. You should choose Gitflow for large-scale enterprise applications that require complex release management, such as maintaining multiple versions simultaneously. Conversely, GitHub Flow is superior for continuous delivery models or smaller teams that deploy to production frequently, as it drastically reduces the administrative overhead associated with managing release and develop branches.
What is the specific procedure for handling an urgent production bug using Gitflow?
When an urgent production bug occurs, Gitflow utilizes a 'hotfix' branch. You start by branching from 'master' using 'git checkout -b hotfix/critical-fix master'. After fixing the issue and committing the changes, you merge the hotfix branch into both 'master' and 'develop'. It is vital to merge into 'develop' to ensure the fix is carried over to future releases. Finally, you tag the release on 'master' to indicate a new production version, which prevents the bug from reappearing in subsequent development cycles.
Why is the use of the '--no-ff' flag considered best practice when merging features in Gitflow?
The '--no-ff' or 'no-fast-forward' flag is essential in Gitflow because it preserves the existence of the feature branch in the project history. Without this flag, Git might perform a fast-forward merge, which simply moves the branch pointer forward, effectively erasing the fact that a separate feature branch ever existed. By forcing a merge commit, you maintain a clear, chronological structure that documents the lifecycle of every feature, which is invaluable for code reviews, debugging, and auditing the project's evolution over time.
Check yourself
1. Which branch is the primary source of truth for the project's history in Gitflow?
- A.feature
- B.develop
- C.main
- D.hotfix
Show answer
C. main
Main represents the production-ready state. Develop is for integration, feature is for individual tasks, and hotfix is for urgent patches; none of these should be considered the permanent record of production deployments like main.
2. Why is it important to merge hotfix branches into both main and develop?
- A.To satisfy Git status requirements.
- B.To ensure the production fix is integrated into the next development cycle.
- C.Because Gitflow requires all branches to be merged twice.
- D.To trigger an automatic deployment to both environments.
Show answer
B. To ensure the production fix is integrated into the next development cycle.
Merging into main fixes the production issue, while merging into develop ensures the fix persists in future releases. Merging only to one creates a regression risk where the fix is lost in the next development cycle.
3. What is the recommended workflow for completing a feature branch in Gitflow?
- A.Merge it directly into main.
- B.Merge it into develop, then delete the feature branch.
- C.Merge it into a release branch for final testing.
- D.Rebase it onto main before merging.
Show answer
B. Merge it into develop, then delete the feature branch.
Features are intended to be integrated into develop. Merging to main is premature; merge to release is non-standard; and rebasing is not a required step for feature completion in the basic Gitflow model.
4. When is it appropriate to create a release branch?
- A.When a new feature is started.
- B.When the develop branch has reached a state of feature completeness for the next release.
- C.When a critical bug is discovered in production.
- D.Every time a developer pushes code to the remote repository.
Show answer
B. When the develop branch has reached a state of feature completeness for the next release.
Release branches are for final prep like documentation and minor bug fixes before a release. Feature start is for features, hotfix is for production bugs, and pushing code is a daily activity, not a release trigger.
5. In Gitflow, what is the purpose of the feature branch naming convention?
- A.To inform GitHub of the priority level.
- B.To allow the Git client to automatically merge the code.
- C.To maintain organization and identify the purpose of the work-in-progress.
- D.To satisfy the requirements for automatic deployment.
Show answer
C. To maintain organization and identify the purpose of the work-in-progress.
Naming conventions like 'feature/' help distinguish work branches from support branches. GitHub doesn't prioritize based on names, Git clients don't auto-merge based on labels, and deployment tools do not rely on branch names for logic.