Sei sulla pagina 1di 8

AsuccessfulGitbranchingmodel

InthispostIpresentthedevelopmentmodelthatIveintroducedforsomeofmyprojects(bothatworkand
private)aboutayearago,andwhichhasturnedouttobeverysuccessful.Ivebeenmeaningtowriteaboutit
forawhilenow,butIveneverreallyfoundthetimetodosothoroughly,untilnow.Iwonttalkaboutanyof
theprojectsdetails,merelyaboutthebranchingstrategyandreleasemanagement.

Itfocusesaround
Git
asthetoolfortheversioningofallofoursourcecode.(Bytheway,ifyoureinterestedin
Git,ourcompany
GitPrime
providessomeawesomerealtimedataanalyticsonsoftwareengineering
performance.)

Whygit?
ForathoroughdiscussionontheprosandconsofGitcomparedtocentralizedsourcecodecontrol
systems,
see
the
web
.Thereareplentyofflamewarsgoingonthere.Asadeveloper,IpreferGitaboveallother
toolsaroundtoday.Gitreallychangedthewaydevelopersthinkofmergingandbranching.Fromtheclassic
CVS/SubversionworldIcamefrom,merging/branchinghasalwaysbeenconsideredabitscary(bewareof
mergeconflicts,theybiteyou!)andsomethingyouonlydoeveryonceinawhile.
ButwithGit,theseactionsareextremelycheapandsimple,andtheyareconsideredoneofthecorepartsof
your
daily
workflow,really.Forexample,inCVS/Subversion
books
,branchingandmergingisfirstdiscussed
inthelaterchapters(foradvancedusers),whilein
every

Git

book
,itsalreadycoveredinchapter3(basics).
Asaconsequenceofitssimplicityandrepetitivenature,branchingandmergingarenolongersomethingtobe
afraidof.Versioncontroltoolsaresupposedtoassistinbranching/mergingmorethananythingelse.
Enoughaboutthetools,letsheadontothedevelopmentmodel.ThemodelthatImgoingtopresenthereis
essentiallynomorethanasetofproceduresthateveryteammemberhastofollowinordertocometoa
managedsoftwaredevelopmentprocess.

Decentralizedbutcentralized
Therepositorysetupthatweuseandthatworkswellwiththisbranchingmodel,isthatwithacentraltruth
repo.Notethatthisrepoisonly
considered
tobethecentralone(sinceGitisaDVCS,thereisnosuchthingas
acentralrepoatatechnicallevel).Wewillrefertothisrepoas
origin
,sincethisnameisfamiliartoallGit
users.

Eachdeveloperpullsandpushestoorigin.Butbesidesthecentralizedpushpullrelationships,eachdeveloper
mayalsopullchangesfromotherpeerstoformsubteams.Forexample,thismightbeusefultoworktogether

withtwoormoredevelopersonabignewfeature,beforepushingtheworkinprogressto
origin
prematurely.
Inthefigureabove,therearesubteamsofAliceandBob,AliceandDavid,andClairandDavid.
Technically,thismeansnothingmorethanthatAlicehasdefinedaGitremote,named
bob
,pointingtoBobs
repository,andviceversa.

Themainbranches

Atthecore,thedevelopmentmodelisgreatlyinspiredbyexisting
modelsoutthere.Thecentralrepoholdstwomainbrancheswithaninfinitelifetime:

master
develop
The
master
branchat
origin
shouldbefamiliartoeveryGituser.Paralleltothe
master
branch,anotherbranch
existscalled
develop.
Weconsider
origin/master
tobethemainbranchwherethesourcecodeof
HEAD
alwaysreflects

a
productionready
state.
Weconsider
origin/develop
tobethemainbranchwherethesourcecodeof
HEAD
alwaysreflectsastatewith
thelatestdelivereddevelopmentchangesforthenextrelease.Somewouldcallthistheintegrationbranch.
Thisiswhereanyautomaticnightlybuildsarebuiltfrom.
Whenthesourcecodeinthe
develop
branchreachesastablepointandisreadytobereleased,allofthechanges
shouldbemergedbackinto
master
somehowandthentaggedwithareleasenumber.Howthisisdoneindetail
willbediscussedfurtheron.
Therefore,eachtimewhenchangesaremergedbackinto
master
,thisisanewproductionrelease
by
definition
.Wetendtobeverystrictatthis,sothattheoretically,wecoulduseaGithookscripttoautomatically
buildandrolloutoursoftwaretoourproductionserverseverytimetherewasacommiton
master
.

Supportingbranches

Nexttothemainbranches
master
and
develop
,ourdevelopmentmodelusesavarietyofsupportingbranchesto
aidparalleldevelopmentbetweenteammembers,easetrackingoffeatures,prepareforproductionreleasesand

toassistinquicklyfixingliveproductionproblems.Unlikethemainbranches,thesebranchesalwayshavea
limitedlifetime,sincetheywillberemovedeventually.
Thedifferenttypesofbrancheswemayuseare:

Feature branches

Release branches

Hotfix branches

Eachofthesebrancheshaveaspecificpurposeandareboundtostrictrulesastowhichbranchesmaybetheir
originatingbranchandwhichbranchesmustbetheirmergetargets.Wewillwalkthroughtheminaminute.
Bynomeansarethesebranchesspecialfromatechnicalperspective.Thebranchtypesarecategorizedby
howwe
use
them.TheyareofcourseplainoldGitbranches.

Featurebranches
May branch off from:
develop

Must merge back into:


develop

Branch naming convention:


anything except
master
,
develop
,
release-*
, or
hotfix-*

Featurebranches(orsometimescalledtopicbranches)areusedtodevelopnew
featuresfortheupcomingoradistantfuturerelease.Whenstartingdevelopmentofa
feature,thetargetreleaseinwhichthisfeaturewillbeincorporatedmaywellbe
unknownatthatpoint.Theessenceofafeaturebranchisthatitexistsaslongasthe
featureisindevelopment,butwilleventuallybemergedbackinto
develop
(to
definitelyaddthenewfeaturetotheupcomingrelease)ordiscarded(incaseofa
disappointingexperiment).
Featurebranchestypicallyexistindeveloperreposonly,notin
origin
.

Creatingafeaturebranch

Whenstartingworkonanewfeature,branchofffromthe
develop
branch.

$git checkout -b myfeature develop


Switched to a new branch "myfeature"

Incorporatingafinishedfeatureondevelop
Finishedfeaturesmaybemergedintothe
develop
branchdefinitelyaddthemtotheupcomingrelease:

$git checkout develop


Switched to branch 'develop'
$git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$git branch -d myfeature
Deleted branch myfeature (was 05e9557).

$git push origin develop

The
--no-ff
flagcausesthemergetoalwayscreateanewcommitobject,evenifthemergecouldbeperformed
withafastforward.Thisavoidslosinginformationaboutthehistoricalexistenceofafeaturebranchandgroups
togetherallcommitsthattogetheraddedthefeature.Compare:

Inthelattercase,itisimpossibletoseefromtheGithistorywhichofthecommitobjectstogetherhave
implementedafeatureyouwouldhavetomanuallyreadallthelogmessages.Revertingawholefeature(i.e.a
groupofcommits),isatrueheadacheinthelattersituation,whereasitiseasilydoneifthe
--no-ff
flagwas
used.
Yes,itwillcreateafewmore(empty)commitobjects,butthegainismuchbiggerthatthatcost.

Releasebranches
May branch off from:
develop

Must merge back into:


develop
and
master

Branch naming convention:


release-*

Releasebranchessupportpreparationofanewproductionrelease.Theyallowforlastminutedottingofisand
crossingts.Furthermore,theyallowforminorbugfixesandpreparingmetadataforarelease(versionnumber,

builddates,etc.).Bydoingallofthisworkonareleasebranch,the
develop
branchisclearedtoreceivefeatures
forthenextbigrelease.
Thekeymomenttobranchoffanewreleasebranchfrom
develop
iswhendevelop(almost)reflectsthedesired
stateofthenewrelease.Atleastallfeaturesthataretargetedforthereleasetobebuiltmustbemergedin
to
develop
atthispointintime.Allfeaturestargetedatfuturereleasesmaynottheymustwaituntilafterthe
releasebranchisbranchedoff.
Itisexactlyatthestartofareleasebranchthattheupcomingreleasegetsassignedaversionnumbernotany
earlier.Upuntilthatmoment,the
develop
branchreflectedchangesforthenextrelease,butitisunclear
whetherthatnextreleasewilleventuallybecome0.3or1.0,untilthereleasebranchisstarted.Thatdecisionis
madeonthestartofthereleasebranchandiscarriedoutbytheprojectsrulesonversionnumberbumping.

Creatingareleasebranch
Releasebranchesarecreatedfromthe
develop
branch.Forexample,sayversion1.1.5isthecurrentproduction
releaseandwehaveabigreleasecomingup.Thestateof
develop
isreadyforthenextreleaseandwehave
decidedthatthiswillbecomeversion1.2(ratherthan1.1.6or2.0).Sowebranchoffandgivethereleasebranch
anamereflectingthenewversionnumber:

$git checkout -b release-1.2 develop


Switched to a new branch "release-1.2"
$./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2.
$git commit -a -m
"Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)
Aftercreatinganewbranchandswitchingtoit,webumptheversionnumber.Here,
bump-version.sh
is
afictionalshellscriptthatchangessomefilesintheworkingcopytoreflectthenewversion.(Thiscanof
coursebeamanualchangethepointbeingthat
some
fileschange.)Then,thebumpedversionnumberis
committed.
Thisnewbranchmayexistthereforawhile,untilthereleasemayberolledoutdefinitely.Duringthattime,bug
fixesmaybeappliedinthisbranch(ratherthanonthe
develop
branch).Addinglargenewfeatureshereis
strictlyprohibited.Theymustbemergedinto
develop
,andtherefore,waitforthenextbigrelease.

Finishingareleasebranch

Whenthestateofthereleasebranchisreadytobecomearealrelease,someactionsneedtobecarriedout.First,
thereleasebranchismergedinto
master
(sinceeverycommiton
master
isanewrelease
bydefinition
,
remember).Next,thatcommiton
master
mustbetaggedforeasyfuturereferencetothishistoricalversion.
Finally,thechangesmadeonthereleasebranchneedtobemergedbackinto
develop
,sothatfuturereleases
alsocontainthesebugfixes.
ThefirsttwostepsinGit:

$git checkout master


Switched to branch 'master'
$git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$git tag -a 1.2
Thereleaseisnowdone,andtaggedforfuturereference.
Edit:
Youmightaswellwanttousethe
-s
or
-u <key>
flagstosignyourtagcryptographically.

Tokeepthechangesmadeinthereleasebranch,weneedtomergethosebackinto
develop
,though.InGit:

$git checkout develop


Switched to branch 'develop'
$git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)

Thisstepmaywellleadtoamergeconflict(probablyeven,sincewehavechangedtheversionnumber).Ifso,
fixitandcommit.
Nowwearereallydoneandthereleasebranchmayberemoved,sincewedontneeditanymore:

$git branch -d release-1.2


Deleted branch release-1.2 (was ff452fe).

Hotfixbranches
May branch off from:
master

Must merge back into:


develop
and
master

Branch naming convention:


hotfix-*

Hotfixbranchesareverymuchlikereleasebranchesinthatthey
arealsomeanttoprepareforanewproductionrelease,albeit
unplanned.Theyarisefromthenecessitytoactimmediatelyupon
anundesiredstateofaliveproductionversion.Whenacritical
buginaproductionversionmustberesolvedimmediately,a
hotfixbranchmaybebranchedofffromthecorrespondingtagon
themasterbranchthatmarkstheproductionversion.
Theessenceisthatworkofteammembers(onthe
develop
branch)
cancontinue,whileanotherpersonispreparingaquickproduction
fix.

Creatingthehotfixbranch
Hotfixbranchesarecreatedfromthe
master
branch.Forexample,sayversion1.2isthecurrentproduction
releaserunningliveandcausingtroublesduetoaseverebug.Butchangeson
develop
areyetunstable.Wemay
thenbranchoffahotfixbranchandstartfixingtheproblem:

$git checkout -b hotfix-1.2.1 master


Switched to a new branch "hotfix-1.2.1"
$./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$git commit -a -m
"Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1

1 files changed, 1 insertions(+), 1 deletions(-)


Dontforgettobumptheversionnumberafterbranchingoff!
Then,fixthebugandcommitthefixinoneormoreseparatecommits.

$git commit -m
"Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
Finishingahotfixbranch
Whenfinished,thebugfixneedstobemergedbackinto
master
,butalsoneedstobemergedbackinto
develop
,
inordertosafeguardthatthebugfixisincludedinthenextreleaseaswell.Thisiscompletelysimilartohow
releasebranchesarefinished.
First,update
master
andtagtherelease.

$git checkout master


Switched to branch 'master'
$git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$git tag -a 1.2.1

Edit:
Youmightaswellwanttousethe
-s
or
-u <key>
flagstosignyourtagcryptographically.
Next,includethebugfixin
develop
,too:

$git checkout develop


Switched to branch 'develop'
$git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)

Theoneexceptiontotherulehereisthat,
whenareleasebranchcurrentlyexists,thehotfixchangesneedto
bemergedintothatreleasebranch,insteadof
develop
.Backmergingthebugfixintothereleasebranchwill
eventuallyresultinthebugfixbeingmergedinto
develop
too,whenthereleasebranchisfinished.(Ifwork
in
develop
immediatelyrequiresthisbugfixandcannotwaitforthereleasebranchtobefinished,youmay
safelymergethebugfixinto
develop
nowalreadyaswell.)
Finally,removethetemporarybranch:

$git branch -d hotfix-1.2.1


Deleted branch hotfix-1.2.1 (was abbe5d6).

Summary
Whilethereisnothingreallyshockingnewtothisbranchingmodel,thebigpicturefigurethatthispostbegan
withhasturnedouttobetremendouslyusefulinourprojects.Itformsanelegantmentalmodelthatiseasyto
comprehendandallowsteammemberstodevelopasharedunderstandingofthebranchingandreleasing
processes.

Potrebbero piacerti anche