doc/user/project/repository/branches/strategies/_index.md
The way you organize and merge Git branches is called a branching strategy. For many teams, the simplest approach is sensible and effective:
main.However, if your team has complex needs (like testing and compliance requirements), you might want to consider a different branching strategy.
The following sections describe some of the more common strategies available. Not everyone has a Git (or version control) specialist on staff. If your team is working at the edges of its Git skill set, this information can help.
When you use GitLab to replace multiple, disparate tools, the decisions you make about your Git branching strategy matter. With careful planning, you can establish clear connections between:
Careful choices help you take the best advantage of the single data store in GitLab.
You might have outgrown your current Git branching strategy if:
Don't implement a strategy that is more complex than your product needs.
Should you maintain one Git repository with a complex branching structure, or split the project across multiple repositories? There's no single right answer. It depends on what you have the personnel and expertise to support.
GitLab provides automation that assumes your repository is for a single product, though that product might contain multiple versions. To determine if you should have multiple repositories, or a single complex one, ask these questions:
No matter what you choose (either a complex single repository, or a set of smaller repositories) you should expect to spend engineering time on maintenance. Identify which type of engineering work you are prepared to do:
[!note] If your organization uses a large monorepo or a megarepo, the Professional Services team at GitLab can help you construct a custom branching solution that meets your needs.
Branching and code management strategies depend on your product's needs. No pre-existing strategy can cover them all, but some major categories are:
This strategy follows standard Git practices. The main branch is your production branch, which
is great for a single web service: there's one canonical production version, and no support for
previous revisions.
For this configuration, git-flow
probably works for you. It's standardized, and you don't have to maintain anything.
In this example, feature-1 branches off directly from main. When complete, feature-1 merges back
directly into main. This merge commit is highlighted with a square. Longer-lived branches, like
feature-2, might periodically merge in the latest updates from main as part of development.
When complete, feature-2 merges into main, and release 1.1 is cut:
%%{init: { "gitGraph": { "mainBranchOrder" : 1 }, "fontFamily": "GitLab Sans" }}%%
gitGraph
accTitle: Branching strategy for web services
accDescr: Feature work happens on separate branches that merge directly into the main branch with release tags.
commit tag: "1.0" id: "release v1.0"
branch "feature-1"
commit id: "start feature-1"
checkout main
commit id: "start feature-2"
branch "feature-2" order: 3
checkout feature-1
commit id: "refine feature-1"
checkout main
merge feature-1 type: HIGHLIGHT id: "merge feature-1 into main"
checkout feature-2
commit id: "build feature 2"
merge main type: HIGHLIGHT id: "merge main into feature-2"
commit
checkout main
merge feature-2 tag: "1.1" type: HIGHLIGHT id: "release v1.1"
This branching strategy is appropriate if your product has branches that must remain separate from main
for a long time. Some examples include:
If you intend to lock a long-lived branch, it is critical to define your hotfix process and enforce it. If undefined and unenforced, every change becomes a hotfix.
In this example, the 2.0 branch is created from the commit on main for the 1.0 release.
Features branch off from the 2.0 branch, and merge back into 2.0. At the same time, any hotfix
branches are based off of the most recent release (1.0) of main, and merge back into main as
release 1.1. The 2.0 branch then pulls in the changes from release 1.1, and incorporates them
as part of the development of 2.0. After the addition of another feature (feature-2), the 2.0
branch is ready for production. It merges into main, and release 2.0 is cut:
%%{init: { "gitGraph": { "mainBranchOrder" : 2 }, "fontFamily": "GitLab Sans" }}%%
gitGraph
accTitle: Branching strategy for long-lived releases
accDescr: Hotfixes merge into the main branch while features are developed on a separate long-lived release branch.
commit tag: "1.0"
branch hotfix order: 1
checkout main
branch "2.0" order: 3
commit
checkout hotfix
commit id: "security bug"
commit id: "performance bug"
checkout "2.0"
branch feature-1 order: 4
commit id: "create feature 1"
checkout main
commit id: " "
checkout 2.0
merge feature-1 id:"merge feature-1" tag: "2.0 RC 1"
checkout main
merge hotfix tag: "1.1" type: HIGHLIGHT
checkout 2.0
merge main tag: "2.0 RC 2" type: HIGHLIGHT
branch feature-2 order: 5
commit id: "create feature 2"
commit id: "refine feature 2"
checkout 2.0
merge feature-2 id: "merge feature-2" tag: "2.0 RC 3"
checkout main
merge 2.0 tag: "2.0" type: HIGHLIGHT
Legacy projects migrating from SVN to Git should review their branching approach. Some SVN-centric branching approaches in Git can prevent you from getting the most out of GitLab. Some workflows to revisit:
1.0) from main, then lock the 1.0 branch to block any
change that is not a pre-approved hotfix.
This branching strategy is common for organizations with multiple interdependent services that are built by different teams. It's often used with waterfall or V-model development processes.
In this example, the commit marked v1.1 RC1 is identified as a release candidate for version 1.1.
Features continue to branch from and back into main, while the release candidate commit is tested on
the test and UAT environments. This process is repeated for each commit that is considered for release:
%%{init: { "fontFamily": "GitLab Sans" }}%%
gitGraph
accTitle: Branching strategy for environment isolation
accDescr: Feature work happens on separate branches while release candidates progress through test and UAT branches for validation.
commit id: "start feature"
branch feature-1
checkout main
commit tag: "v1.1 RC1" id: "start testing"
branch test
checkout feature-1
commit id: "develop feature"
commit id: "refine feature"
checkout test
commit id: " " tag: "v1.1 RC1"
branch UAT
checkout UAT
commit tag: "v1.1"
checkout main
merge feature-1 id: "merge feature-1"
commit