GitHub Flow

Problemen met git-flow

Ik reis overal naar toe om Git aan mensen te leren en bijna elke les en workshop die ik de laatste tijd heb gedaan heeft me gevraagd wat ik van git-flow vind. Ik antwoord altijd dat ik het geweldig vind – het heeft een systeem (Git) genomen dat een miljoen mogelijke workflows heeft en heeft een goed geteste, flexibele workflow gedocumenteerd die voor veel ontwikkelaars werkt op een vrij eenvoudige manier. Het is een soort standaard geworden, zodat ontwikkelaars tussen projecten of bedrijven kunnen verhuizen en bekend zijn met deze gestandaardiseerde werkwijze.

Hoewel, het heeft ook zijn problemen. Ik heb een aantal meningen van mensen gehoord in de trant van het niet leuk vinden dat nieuwe feature branches worden gestart vanaf develop in plaats van master, of de manier waarop het hotfixes behandelt, maar die zijn vrij klein.

Een van de grotere problemen voor mij is dat het ingewikkelder is dan ik denk dat de meeste ontwikkelaars en ontwikkelingsteams eigenlijk nodig hebben. Het is ingewikkeld genoeg dat er een groot helper script is ontwikkeld om de flow te helpen afdwingen. Hoewel dit cool is, is het probleem dat het niet afgedwongen kan worden in een Git GUI, alleen op de commandoregel, dus de enige mensen die de complexe workflow echt goed moeten leren, omdat ze alle stappen handmatig moeten doen, zijn dezelfde mensen die niet comfortabel genoeg met het systeem zijn om het vanaf de commandoregel te gebruiken. Dit kan een enorm probleem zijn.

Beide van deze problemen kunnen gemakkelijk worden opgelost door gewoon een veel eenvoudiger proces te hebben. Bij GitHub, gebruiken we geen git-flow. We gebruiken, en hebben altijd gebruikt, een veel eenvoudigere Git-workflow.

Dankzij zijn eenvoud heeft het een aantal voordelen. Een ervan is dat het makkelijk te begrijpen is voor mensen, wat betekent dat ze het snel kunnen oppikken en dat ze zelden of nooit fouten maken of stappen die ze verkeerd deden ongedaan moeten maken. Een ander is dat we geen wrapper script nodig hebben om het af te dwingen of te volgen, dus het gebruik van GUIs en dergelijke is geen probleem.

GitHub Flow

Dus, waarom gebruiken we git-flow niet bij GitHub? Nou, het belangrijkste probleem is dat we de hele tijd deployen. Het git-flow proces is grotendeels ontworpen rond de “release”. We hebben niet echt “releases” omdat we elke dag deployen naar productie – vaak meerdere keren per dag. Dat doen we via onze chatroom-robot, die dezelfde plaats is als waar onze CI resultaten getoond worden. We proberen het proces van testen en verzenden zo eenvoudig mogelijk te maken, zodat iedere medewerker zich er prettig bij voelt.

Er zijn een aantal voordelen aan het zo regelmatig uitrollen. Als je om de paar uur uitrolt, is het bijna onmogelijk om grote aantallen bugs te introduceren. Kleine problemen kunnen worden geïntroduceerd, maar dan kunnen ze zeer snel worden opgelost en opnieuw uitgerold. Normaal gesproken zou je een ‘hotfix’ moeten doen of iets buiten het normale proces om, maar het is gewoon onderdeel van ons normale proces – er is geen verschil in de GitHub flow tussen een hotfix en een hele kleine feature.

Een ander voordeel van het altijd deployen is de mogelijkheid om snel allerlei soorten issues aan te pakken. We kunnen reageren op beveiligingsproblemen die onder onze aandacht worden gebracht of kleine maar interessante functieverzoeken ongelooflijk snel implementeren, maar we kunnen precies hetzelfde proces gebruiken om die wijzigingen aan te pakken als we doen om normale of zelfs grote functie-ontwikkeling te behandelen. Het is allemaal hetzelfde proces en het is allemaal heel eenvoudig.

Hoe we het doen

Dus, wat is GitHub Flow?

  • Alles in de master branch is deployable
  • Om aan iets nieuws te werken, maak je een beschrijvende naam branch aan van master (bijv: new-oauth2-scopes)
  • Commiteer lokaal op die branch en zet uw werk regelmatig terug naar dezelfde genoemde branch op de server
  • Wanneer u feedback of hulp nodig heeft, of u denkt dat de branch klaar is om samengevoegd te worden, open je een pull request
  • Als iemand anders de functie heeft beoordeeld en afgetekend, kun je hem samenvoegen in master
  • Als hij eenmaal is samengevoegd en naar ‘master’ is gepushed, kun en moet je hem meteen deployen

Dat is de hele flow. Het is erg simpel, erg effectief en werkt voor redelijk grote teams – GitHub is nu 35 werknemers, waarvan er misschien 15-20 tegelijkertijd aan hetzelfde project (github.com) werken. Ik denk dat de meeste ontwikkelteams – groepen die op hetzelfde moment aan dezelfde logische code werken wat conflicten zou kunnen opleveren – rond deze grootte of kleiner zijn. Vooral degenen die progressief genoeg zijn om snelle en consistente implementaties te doen.

Dus, laten we eens kijken naar elk van deze stappen op hun beurt.

#1 – alles in de master branch is implementeerbaar

Dit is in principe de enige harde regel van het systeem. Er is maar één branch die een specifieke en consistente betekenis heeft en we hebben hem master genoemd. Voor ons betekent dit dat het al uitgerold is of in het slechtste geval binnen enkele uren uitgerold zal worden. Het is ongelofelijk zeldzaam dat deze teruggerold wordt (de branch wordt teruggeplaatst naar een oudere commit om werk terug te draaien) – als er een probleem is, worden commits teruggedraaid of nieuwe commits geïntroduceerd die het probleem oplossen, maar de branch zelf wordt bijna nooit teruggerold.

De master branch is stabiel en het is altijd, altijd veilig om er vanaf te deployen of nieuwe branches van te maken. Als je iets naar master pusht dat niet getest is of de build breekt, breek je het sociale contract van het ontwikkelteam en voel je je daar normaal gesproken behoorlijk slecht over. Elke branch die we pushen heeft tests uitgevoerd en gerapporteerd in de chat room, dus als je ze niet lokaal hebt uitgevoerd, kun je gewoon naar een onderwerp branch pushen (zelfs een branch met een enkele commit) op de server en wachten op Jenkins om je te vertellen of het alles haalt.

Je zou een deployed branch kunnen hebben die alleen wordt bijgewerkt als je deployed, maar dat doen we niet. We tonen gewoon de huidige ingezette SHA via de webapp zelf en curl het als we een vergelijking nodig hebben.

#2 – maak beschrijvende takken van master

Wanneer je ergens aan wilt gaan werken, maak je een beschrijvende naam branch van de stabiele master branch. Enkele voorbeelden in de GitHub codebase op dit moment zouden user-content-cache-key, submodules-init-task of redis2-transition zijn. Dit heeft verschillende voordelen – een is dat als je fetched, je de onderwerpen kunt zien waar iedereen aan gewerkt heeft. Een ander is dat als je een branch een tijdje verlaat en er later naar teruggaat, het vrij makkelijk is om te onthouden wat het was.

Dit is leuk omdat wanneer we naar de GitHub branch lijst pagina gaan, we makkelijk kunnen zien aan welke branches er recent gewerkt is en hoeveel werk er ongeveer op zit.

github branch list

Het is bijna als een lijst met aankomende features met de huidige ruwe status. Deze pagina is geweldig als je het niet gebruikt – het laat je alleen branches zien waar uniek werk op zit ten opzichte van je huidige geselecteerde branch en het sorteert ze zo dat de branches waar het meest recent aan gewerkt is bovenaan staan. Als ik echt nieuwsgierig word, kan ik op de ‘Vergelijk’ knop klikken om te zien wat de werkelijke verenigde diff en commit lijst is die uniek is voor die tak.

Zo, op het moment van schrijven, hebben we 44 takken in ons repository met ongefuseerd werk erin, maar ik kan ook zien dat er maar ongeveer 9 of 10 van hen gepushed zijn in de afgelopen week.

#3 – push constant naar genoemde branches

Een ander groot verschil met git-flow is dat we constant pushen naar genoemde branches op de server. Omdat het enige waar we ons echt zorgen over hoeven te maken master is vanuit een deployment standpunt, brengt het pushen naar de server niemand in de war of verwart het dingen – alles dat niet master is, is gewoon iets waar aan gewerkt wordt.

Het zorgt er ook voor dat ons werk altijd gebackupt is in het geval van laptop verlies of harde schijf uitval. Nog belangrijker, het zet iedereen in constante communicatie. Een simpele ‘git fetch’ geeft je in principe een TODO-lijst van waar iedereen op dit moment aan werkt.

$ git fetchremote: Counting objects: 3032, done.remote: Compressing objects: 100% (947/947), done.remote: Total 2672 (delta 1993), reused 2328 (delta 1689)Receiving objects: 100% (2672/2672), 16.45 MiB | 1.04 MiB/s, done.Resolving deltas: 100% (1993/1993), completed with 213 local objects.From github.com:github/github * charlock-linguist -> origin/charlock-linguist * enterprise-non-config -> origin/enterprise-non-config * fi-signup -> origin/fi-signup 2647a42..4d6d2c2 git-http-server -> origin/git-http-server * knyle-style-commits -> origin/knyle-style-commits 157d2b0..d33e00d master -> origin/master * menu-behavior-act-i -> origin/menu-behavior-act-i ea1c5e2..dfd315a no-inline-js-config -> origin/no-inline-js-config * svg-tests -> origin/svg-tests 87bb870..9da23f3 view-modes -> origin/view-modes * wild-renaming -> origin/wild-renaming

Het laat iedereen ook zien, door op de GitHub Branch List pagina te kijken, waar iedereen anders aan werkt zodat ze die kunnen inspecteren en kijken of ze ergens mee willen helpen.

#4 – open een pull request op elk moment

GitHub heeft een geweldig code review systeem genaamd Pull Requests waar, vrees ik, niet genoeg mensen van weten. Veel mensen gebruiken het voor open source werk – fork een project, update het project, stuur een pull request naar de maintainer. Het kan echter ook gemakkelijk worden gebruikt als een intern code review systeem, wat is wat wij doen.

Eigenlijk gebruiken we het meer als een branch conversation view dan een pull request. Je kunt pull requests van de ene branch naar de andere sturen in een enkel project (publiek of privé) in GitHub, dus je kunt ze gebruiken om te zeggen “Ik heb hier hulp of beoordeling bij nodig” in aanvulling op “Voeg dit alsjeblieft samen”.

vroeg pr-bericht

Hier kun je zien dat Josh Brian cc’t voor beoordeling en dat Brian binnenkomt met wat advies over een van de regels code. Verderop ziet u dat Josh de zorgen van Brian erkent en meer code doorstuurt om ze aan te pakken.

meer discussie

Ten slotte kunt u zien dat we nog steeds in de testfase zitten – dit is nog geen tak die klaar is voor implementatie, we gebruiken de Pull Requests om de code te beoordelen lang voordat we deze daadwerkelijk willen samenvoegen in master voor implementatie.

Als je vastzit in de voortgang van je functie of branch en hulp of advies nodig hebt, of als je een ontwikkelaar bent en een ontwerper nodig hebt om je werk te beoordelen (of vice versa), of zelfs als je weinig of geen code hebt maar wel wat screenshot comps of algemene ideeën, dan open je een pull-request. Je kunt mensen in het GitHub systeem cc-en door een @ gebruikersnaam toe te voegen, dus als je de beoordeling of feedback van specifieke mensen wilt, dan cc je ze gewoon in het PR bericht (zoals je Josh hierboven zag doen).

Dit is cool omdat de Pull Request functie je commentaar laat geven op individuele regels in de unified diff, op enkele commits of op het pull verzoek zelf en alles inline naar een enkele conversatie view trekt.Het laat je ook doorgaan om naar de branch te pushen, dus als iemand commentaar geeft dat je iets vergeten bent te doen of als er een bug in de code zit, dan kun je het fixen en naar de branch pushen, GitHub zal de nieuwe commits in de conversatie weergave laten zien en je kunt zo op een branch blijven itereren.

Als de branch te lang open is geweest en je voelt dat het niet meer synchroon loopt met de master branch, dan kun je master in je onderwerp branch samenvoegen en door blijven gaan. Je kunt gemakkelijk in de pull request discussie of commit lijst zien wanneer de branch voor het laatst is samengevoegd met de ‘master’.

master merge

Als alles echt klaar is op de branch en je vindt dat hij klaar is om te deployen, dan kun je naar de volgende stap gaan.

#5 – alleen samenvoegen na beoordeling pull-request

We werken niet zomaar direct aan master of werken aan een onderwerp branch en voegen het samen als we denken dat het klaar is – we proberen eerst toestemming te krijgen van iemand anders in het bedrijf. Dit is meestal een +1 of emoji of “:shipit:” commentaar, maar we proberen iemand anders er naar te laten kijken.

shipit commentaar

Als we dat hebben, en de branch door CI is gekomen, kunnen we het samenvoegen in master voor deployment, wat automatisch de Pull Request zal sluiten als we het pushen.

#6 – deploy onmiddellijk na review

Eindelijk is je werk klaar en samengevoegd in de master branch. Dit betekent dat zelfs als je het nu niet uitrolt, mensen er nieuw werk op zullen baseren en de volgende uitrol, die waarschijnlijk binnen een paar uur zal gebeuren, zal het uitrollen. Dus omdat je echt niet wilt dat iemand anders iets pusht dat jij hebt geschreven en dat dingen breekt, hebben mensen de neiging om ervoor te zorgen dat het echt stabiel is wanneer het wordt samengevoegd en mensen hebben ook de neiging om hun eigen wijzigingen te pushen.

Onze kampvuur bot, hubot, kan deployments doen voor elk van de medewerkers, dus een eenvoudige:

hubot depoy github to production

zal de code deployen en zero-downtime alle noodzakelijke processen opnieuw opstarten. Je kunt zien hoe vaak dit voorkomt op GitHub:

onze kampvuur logs

Je kunt 6 verschillende mensen zien (waaronder een ondersteuningsman en een ontwerper) die ongeveer 24 keer op één dag deployen.

Ik heb dit gedaan voor branches met één commit die een verandering van één regel bevat. Het proces is eenvoudig, rechttoe rechtaan, schaalbaar en krachtig. Je kunt het doen met feature branches met 50 commits erop die 2 weken duurden, of 1 commit die 10 minuten duurde. Het is zo’n eenvoudig en wrijvingsloos proces dat je niet geïrriteerd bent dat je het moet doen, zelfs niet voor 1 commit, wat betekent dat mensen zelden proberen om het proces over te slaan of te omzeilen, tenzij de verandering zo klein of onbeduidend is dat het gewoon niet uitmaakt.

Dit is een ongelofelijk eenvoudig en krachtig proces. Ik denk dat de meeste mensen het er mee eens zullen zijn dat GitHub een zeer stabiel platform heeft, dat problemen snel worden aangepakt als ze al ooit opduiken, en dat nieuwe functies in een snel tempo worden geïntroduceerd. Er is geen compromis van kwaliteit of stabiliteit zodat we meer snelheid of eenvoud of minder proces kunnen krijgen.

Conclusie

Git zelf is redelijk complex om te begrijpen, de workflow die je ermee gebruikt complexer maken dan nodig is gewoon meer mentale overhead toevoegen aan ieders dag. Ik zou er altijd voor pleiten om het eenvoudigst mogelijke systeem te gebruiken dat werkt voor je team en dat te doen tot het niet meer werkt en dan alleen complexiteit toe te voegen als het absoluut nodig is.

Voor teams die formele releases moeten doen op langere termijn (een paar weken tot een paar maanden tussen releases), en in staat zijn om hot-fixes en onderhoudstakken te doen en andere dingen die ontstaan door zo onregelmatig te verschepen, is git-flow zinnig en ik zou het gebruik ervan ten zeerste aanbevelen.

Voor teams die een cultuur van verschepen hebben opgezet, die elke dag naar productie pushen, die constant aan het testen en deployen zijn, zou ik ervoor pleiten om iets eenvoudigers als GitHub Flow te kiezen.

Leave a Reply