{"id":309,"date":"2026-10-13T12:21:52","date_gmt":"2026-10-13T12:21:52","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2012\/01\/07\/a-successful-git-branching-model\/"},"modified":"2026-10-13T12:21:52","modified_gmt":"2026-10-13T12:21:52","slug":"a-successful-git-branching-model","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/a-successful-git-branching-model\/","title":{"rendered":"Gitflow Branching Model: Practical Guide to Feature, Release, and Hotfix Branches"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This guide explains the classic Gitflow-style branching model: two long-lived branches for stability, plus short-lived branches for features, releases, and emergency fixes. It is useful for DevOps and engineering teams that need parallel development with controlled production releases.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Originally published on 2012-01-07; fully revised and updated.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This article was originally posted as a repost of a well-known Git branching approach. Useful original references are preserved: <a href=\"http:\/\/git-scm.com\/\">Git<\/a>, <a href=\"http:\/\/whygitisbetterthanx.com\/\">Why Git Is Better Than X<\/a>, and <a href=\"http:\/\/www.looble.com\/git-vs-svn-which-is-better\/\">Git vs SVN<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2012\/01\/git-branching-mode.png\" alt=\"Git branching model overview\" \/><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How this model is organized<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The model keeps one shared repository (commonly called <code>origin<\/code>) as the team reference point, while still using Git&#8217;s distributed workflow. Developers can collaborate through <code>origin<\/code> and, when needed, add each other as remotes for peer collaboration.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><code>master<\/code><\/strong> (often <code>main<\/code> in modern repos): production-ready history.<\/li><li><strong><code>develop<\/code><\/strong>: integration branch for upcoming release work.<\/li><li><strong>Feature branches<\/strong>: isolated implementation work, merged back to <code>develop<\/code>.<\/li><li><strong>Release branches<\/strong>: release hardening, version prep, and final validation.<\/li><li><strong>Hotfix branches<\/strong>: urgent production fixes branched from <code>master<\/code>.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Branch types and merge rules<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Branch type<\/th><th>Create from<\/th><th>Merge into<\/th><th>Primary purpose<\/th><th>Naming pattern<\/th><\/tr><\/thead><tbody><tr><td><code>master<\/code> (or <code>main<\/code>)<\/td><td>Long-lived branch<\/td><td>Not applicable<\/td><td>Tracks production-ready commits<\/td><td><code>master<\/code> or <code>main<\/code><\/td><\/tr><tr><td><code>develop<\/code><\/td><td>Long-lived branch<\/td><td><code>master<\/code> at release time<\/td><td>Integrates completed development work<\/td><td><code>develop<\/code><\/td><\/tr><tr><td>Feature branch<\/td><td><code>develop<\/code><\/td><td><code>develop<\/code><\/td><td>Build and test a feature in isolation<\/td><td><code>feature-*<\/code> (or team convention)<\/td><\/tr><tr><td>Release branch<\/td><td><code>develop<\/code><\/td><td><code>master<\/code> and <code>develop<\/code><\/td><td>Stabilize a specific release version<\/td><td><code>release-*<\/code><\/td><\/tr><tr><td>Hotfix branch<\/td><td><code>master<\/code><\/td><td><code>master<\/code> and <code>develop<\/code> (or active release branch)<\/td><td>Patch production quickly<\/td><td><code>hotfix-*<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Typical lifecycle from feature to production<\/h2>\n\n\n\n<pre class=\"mermaid\">\nflowchart LR\n    A[develop branch] --> B[feature branch]\n    B --> C[merge to develop]\n    C --> D[release branch]\n    D --> E[merge to master]\n    E --> F[tag version]\n    D --> G[merge back to develop]\n    E --> H[hotfix branch]\n    H --> I[merge to master]\n    H --> J[merge to develop or release]\n    I --> K[tag hotfix]\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Important exception: if a release branch is currently active, merge hotfixes into that release branch first, then back into <code>develop<\/code> when the release branch is completed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Command reference for common Gitflow operations<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Create and merge a feature branch<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\">git checkout develop\ngit pull origin develop\ngit checkout -b feature-login-api\n\n<span class=\"hljs-comment\"># implement and commit changes<\/span>\ngit add .\ngit commit -m <span class=\"hljs-string\">\"feat: add login api\"<\/span>\n\ngit checkout develop\ngit merge --no-ff feature-login-api\ngit push origin develop\ngit branch -d feature-login-api<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Create and finish a release branch<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css language-bash\"><span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">checkout<\/span> <span class=\"hljs-selector-tag\">develop<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">pull<\/span> <span class=\"hljs-selector-tag\">origin<\/span> <span class=\"hljs-selector-tag\">develop<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">checkout<\/span> <span class=\"hljs-selector-tag\">-b<\/span> <span class=\"hljs-selector-tag\">release-1<\/span><span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.0<\/span>\n\n# <span class=\"hljs-selector-tag\">update<\/span> <span class=\"hljs-selector-tag\">version<\/span> <span class=\"hljs-selector-tag\">files<\/span> <span class=\"hljs-selector-tag\">and<\/span> <span class=\"hljs-selector-tag\">release<\/span> <span class=\"hljs-selector-tag\">notes<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">commit<\/span> <span class=\"hljs-selector-tag\">-am<\/span> \"<span class=\"hljs-selector-tag\">chore<\/span>: <span class=\"hljs-selector-tag\">prepare<\/span> <span class=\"hljs-selector-tag\">release<\/span> 1<span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.0<\/span>\"\n\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">checkout<\/span> <span class=\"hljs-selector-tag\">master<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">merge<\/span> <span class=\"hljs-selector-tag\">--no-ff<\/span> <span class=\"hljs-selector-tag\">release-1<\/span><span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.0<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">tag<\/span> <span class=\"hljs-selector-tag\">-a<\/span> 1<span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.0<\/span> <span class=\"hljs-selector-tag\">-m<\/span> \"<span class=\"hljs-selector-tag\">Release<\/span> 1<span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.0<\/span>\"\n\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">checkout<\/span> <span class=\"hljs-selector-tag\">develop<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">merge<\/span> <span class=\"hljs-selector-tag\">--no-ff<\/span> <span class=\"hljs-selector-tag\">release-1<\/span><span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.0<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">branch<\/span> <span class=\"hljs-selector-tag\">-d<\/span> <span class=\"hljs-selector-tag\">release-1<\/span><span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.0<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">push<\/span> <span class=\"hljs-selector-tag\">origin<\/span> <span class=\"hljs-selector-tag\">master<\/span> <span class=\"hljs-selector-tag\">develop<\/span> <span class=\"hljs-selector-tag\">--tags<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Create and finish a hotfix branch<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css language-bash\"><span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">checkout<\/span> <span class=\"hljs-selector-tag\">master<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">pull<\/span> <span class=\"hljs-selector-tag\">origin<\/span> <span class=\"hljs-selector-tag\">master<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">checkout<\/span> <span class=\"hljs-selector-tag\">-b<\/span> <span class=\"hljs-selector-tag\">hotfix-1<\/span><span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.1<\/span>\n\n# <span class=\"hljs-selector-tag\">fix<\/span> <span class=\"hljs-selector-tag\">production<\/span> <span class=\"hljs-selector-tag\">issue<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">commit<\/span> <span class=\"hljs-selector-tag\">-am<\/span> \"<span class=\"hljs-selector-tag\">fix<\/span>: <span class=\"hljs-selector-tag\">resolve<\/span> <span class=\"hljs-selector-tag\">critical<\/span> <span class=\"hljs-selector-tag\">production<\/span> <span class=\"hljs-selector-tag\">issue<\/span>\"\n\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">checkout<\/span> <span class=\"hljs-selector-tag\">master<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">merge<\/span> <span class=\"hljs-selector-tag\">--no-ff<\/span> <span class=\"hljs-selector-tag\">hotfix-1<\/span><span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.1<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">tag<\/span> <span class=\"hljs-selector-tag\">-a<\/span> 1<span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.1<\/span> <span class=\"hljs-selector-tag\">-m<\/span> \"<span class=\"hljs-selector-tag\">Hotfix<\/span> 1<span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.1<\/span>\"\n\n# <span class=\"hljs-selector-tag\">if<\/span> <span class=\"hljs-selector-tag\">no<\/span> <span class=\"hljs-selector-tag\">active<\/span> <span class=\"hljs-selector-tag\">release<\/span> <span class=\"hljs-selector-tag\">branch<\/span> <span class=\"hljs-selector-tag\">exists<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">checkout<\/span> <span class=\"hljs-selector-tag\">develop<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">merge<\/span> <span class=\"hljs-selector-tag\">--no-ff<\/span> <span class=\"hljs-selector-tag\">hotfix-1<\/span><span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.1<\/span>\n\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">branch<\/span> <span class=\"hljs-selector-tag\">-d<\/span> <span class=\"hljs-selector-tag\">hotfix-1<\/span><span class=\"hljs-selector-class\">.2<\/span><span class=\"hljs-selector-class\">.1<\/span>\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">push<\/span> <span class=\"hljs-selector-tag\">origin<\/span> <span class=\"hljs-selector-tag\">master<\/span> <span class=\"hljs-selector-tag\">develop<\/span> <span class=\"hljs-selector-tag\">--tags<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Optional: enforce non fast forward merges by default<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\">git config --<span class=\"hljs-keyword\">global<\/span> merge.ff <span class=\"hljs-keyword\">false<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Gitflow compared with trunk-based development<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Approach<\/th><th>Best for<\/th><th>Release style<\/th><th>Operational trade-off<\/th><\/tr><\/thead><tbody><tr><td>Gitflow<\/td><td>Teams that need staged releases and explicit release hardening<\/td><td>Versioned releases via release branches and tags<\/td><td>Clear structure, but more branch management overhead<\/td><\/tr><tr><td>Trunk-based development<\/td><td>Teams shipping very frequently with strong CI and feature flagging<\/td><td>Continuous integration on a short-lived branch model<\/td><td>Faster flow, but requires strict discipline and automation maturity<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Common pitfalls and best practices<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Protect long-lived branches.<\/strong> Require pull requests, reviews, and CI checks on <code>master<\/code>\/<code>main<\/code> and <code>develop<\/code>.<\/li><li><strong>Always back-merge fixes.<\/strong> Every release or hotfix change must be merged back so future releases do not regress.<\/li><li><strong>Keep release branches short-lived.<\/strong> Treat them as stabilization branches, not feature branches.<\/li><li><strong>Tag every production release.<\/strong> Tags make rollback and auditing much easier.<\/li><li><strong>Use one naming convention.<\/strong> Keep branch names predictable for automation and team clarity.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For historical context from the original repost, the diagram source archive is still linked here: <a href=\"http:\/\/github.com\/downloads\/nvie\/gitflow\/Git-branching-model-src.key.zip\">gitflow-model.src.key<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how the classic Gitflow model organizes development with long-lived and short-lived branches. This guide covers branch rules, workflow, and production-ready Git command examples.<\/p>\n","protected":false},"author":1,"featured_media":3855,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[38],"tags":[2213,160,2607,2217,2613,2605,2610,2608,2609,2612,545,1692,593,2606,2611,213],"class_list":["post-309","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-git","tag-branching","tag-git","tag-git-branches","tag-git-branching","tag-git-branching-guide","tag-git-branching-model","tag-git-branching-model-guide","tag-git-branching-model-tutorial","tag-git-branching-model-workflow","tag-git-branching-tutorial","tag-how","tag-model","tag-process","tag-successful-git-branching-model","tag-successful-git-branching-tutorial","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/309","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=309"}],"version-history":[{"count":4,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/309\/revisions"}],"predecessor-version":[{"id":79165,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/309\/revisions\/79165"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3855"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=309"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=309"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=309"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}