---
# System prepended metadata

title: Git strategier

---

# Git strategier
Der er flere planer at arbejde på, når vi taler om Git- og deploy strategier.

## Hvad snakker vi om
* Der findes forskellige velbeskrevne **workflows** eller **branching strategier** - og nogle er mere avancerede end andre. Alle har til formål at sikre en konsistent måde at branche og merge på. 
* Der findes standarder for hvordan **commit-beskeder** skrives - hvilket bl.a. muliggør automatisk changelog vha tools.
* **Versionsnummer** tildeles med "[semantic versioning](https://semver.org/)". Der findes tools som automatisk kan bestemme nye versionsnumre ved at sammenholde eksisterende versionsnummer med indeværende commit-beskeder. Versionsnummer persisteres typisk både i en fil og som et git-tag.
* Der er forskellige processer som anbefales i forbindelse med **release** (deploy) af nye versioner. Disse berører typisk det overordnede workflow og i nogle tilfælde også versionering.

# Workflows
## Gitflow
[Gitflow](https://nvie.com/posts/a-successful-git-branching-model/) er et meget ubredt (og omdiskuteret) workflow. Det beskriver en strategi som inkluderer feature branches, release branches og hotfix branches foruden develop og master.

**Master** branchen reflekterer til enhver tid en produktionsklar og stabil kode. 

**Develop** har til formål at danne fundament for features - dvs man laver feature branches ud herfra og merger dem ind igen når de er klar.

**Feature branches** implementeres og tilrettes i hver deres branch som stammer fra develop. Foruden hotfixes omtaler workflow'et ikke bugs.

**Release branches** For hvert release/deploy laves en ny branch hvori der sættes versionsnummer forud for deploy. 

**Hotfix branches** Såfremt det skønnes nødvendigt at lave et hotfix, sker dette ved at branche ud fra master eller en given release branch, implementere sit hotfix, og så merge ændringerne tilbage til master og develop.

![](https://wac-cdn.atlassian.com/dam/jcr:61ccc620-5249-4338-be66-94d563f2843c/05%20(2).svg?cdnVersion=1489)

## GitHub-Flow
[Dette flow](http://scottchacon.com/2011/08/31/github-flow.html) fra GitHub selv beskriver en meget simpel strategi som egentlig blot går ud på at:
* Branch ud fra master
* Implementer ændringer (commits)
* Åbn et PR
* Drøft ændringerne. Evt implementer flere ændringer (commits)
* Evt deploy fra feature branch
* Merge til master 
* Evt deploy fra master

![](https://media-exp1.licdn.com/dms/image/C4D12AQGMmY2eCKVquQ/article-cover_image-shrink_600_2000/0/1559283797939?e=1619654400&v=beta&t=U13dgTut7-GhUi3DtIaQl1K-MieLk2Ec03mnHyBxsT8)

Der er mange fordele ved dette ret simple flow, og det er også det jeg selv er tilbøjelig til at anbefale. En af de fordele som forfatteren fremhæver er, at hvis man ellers husker at slette branches når man er færdig med dem, så kan branch-listen fungere som et ret fint overblik over features som er på vej ind i kodebasen.

Der findes forskellige varianter af GitHub-Flow, fx [dette fra Atlassian](https://www.atlassian.com/git/articles/simple-git-workflow-is-simple) som introducerer jævnlig rebasing af master ind i feature branch'en.

## GitLab Flow
[GitLab](https://about.gitlab.com) som tilbyder mange af de samme features som GitHub har selvfølgelig også deres bud på en strategi, nemlig [GitLab Flow](https://gitlab.gbar.dtu.dk/help/workflow/gitlab_flow.md). De  væsentligste forskelle er
* PR oprettes umiddelbart efter oprettelsen af feature branch'en. 
  * Dermed lægges der mere op til kommunikation omkring ændringerne helt fra starten af implementeringen
* Master branch er default branch og der deploy'es fra **production**. 
  * Der kan let tilføjes branches til forskellige miljøer, fx **pre-production**, **test** osv.

![](https://i.imgur.com/QuoYPsB.png)

![](https://about.gitlab.com/images/gitlab-flow/gitlab-flow.svg)

## Three-Flow
Et helt andet alternativ, [Three-Flow](https://www.nomachetejuggling.com/2017/04/09/a-different-branching-strategy/), går lodret imod brugen af feature branches, og anbefaler i stedet commits direkte i master. Ikke-færdige features bypass'es ved hjælp af "Feature toggles", fx:
```
if(newCodeEnabled) {
	/*new code*/
} else {
	/*old code*/
}
```

Disse toggles kan sættes dynamisk, og giver tillige mulighed for at konfigurere funktionalitet og features via config filer, i databasen eller helt eksternt hvorved features kan slås til og fra uden redeploys.

Foruden **master** branch'en omtaler Three-Flow to andre branches som lever permanent:
* **candidate** som branches fra master og hvori der commites bugfixes som så merges tilbage i master.
* **release** som branches fra candidate og hvorfra der deploy'es.

Hotfixes kan også commit'es direkte til release - og de merges så tilbage til både candidate og master. 

![](https://www.nomachetejuggling.com/assets/three-flow.png)

Det er denne brug af kun 3 branches der har lagt navn til flow'et.

# Branch navngivning og Commit beskeder
Alt efter hvilket workflow man vælger at tage til sig, er der forskellige retningslinjer med hensyn til navngivning af branches. Vælger man at anvende feature branches, vil det være naturligt at navngive dem efter det Jira-issue som de er opstået af. Jeg er ikke stødt på nogen anbefalinger som skelner imellem features, bugs og andet på branch-niveau. Dvs navne som "GAR-242" burde være dækkende.

De enkelte commit-beskeder kan med fordel følge Conventional Git. Det er en udbredt standard som ikke alene letter overblikket for de som gennemser commit-history, men også muliggør automatiseret changelog-generering og udregning af næste versionsnummer. Der findes forskellige varianter, hvoraf Angular, som arbejder med flere forskellige "types" af commits, har været anvendt i det gamle API-team. 

### Kort om Conventional Commits
Der er blot tale om en vedtagen syntax som består af type og besked samt angivelse af om ændringen er "breaking".

Her er et commit af typen "refactor". Udråbstegnet angiver at det er en ikke-bagud kompatibel (dvs "breaking") ændring. 
```
refactor!: drop support for PHP 5
```
Bemærk at der ikke startes med stort, og at der ikke afsluttes med punktum.

Hvis man har en længere commit-besked, inddeles denne i en body- og en footersektion:
```
fix: correct minor typos in code

see the issue for details

on typos fixed.

Reviewed-by: Z
Refs #GAR-242
```

[Læs mere...](https://www.conventionalcommits.org/en/v1.0.0/)

## Squashed Pull Requests
Når feature branches merges til main line (om det så er master eller develop) kan det være en ide at squash'e sine commits, sådan at de i sidste ende fremtsår som et enkelt commit i stedet for en hel masse bittesmå ændringer hvoraf mange vil være trivielle.

# Automatisering
## CLI tools
Git i sig selv kan betjenes på forskellige måder. Der findes en mængde grafiske tools såsom Gitkraken, SourceTree og Tower. PhpStorm har en indbygget Git GUI og til Visual Studio Code findes der også flere plugins som bidrager til en visuel betjening. Det er dog mit indtryk at de fleste af os benytter `git` via command line'n. Vælger man et af de mere etablerede workflows, som fx "gitflow" findes der tilmed tools som understøtter og letter det daglige arbejde med branching og merging - men man kan selvfølgelig argumentere for at det sker på bekostning af noget gennemsigtighed.

## Deploys
Begge de gamle teams har valgt at deploys håndteres manuelt. Rent teknisk er det muligt at gennemføre deploys automatiseret. Det kan enten initieres fra udviklerens maskine som en del af et workflow eller det kan ske fra github fx når allle checks i en specific branch har kørt fejlfrit. Med henvisning til hvor mange forskellige platforme vi releaser til, er det nok mest realistisk at fortsætte med en håndholdt procedure indtil videre men med fremtidigt fokus på at automatisere deploys til DR Pipeline.

## CI/CD tools
Vi har allerede i dag flere forskellige jobs som afvikles automatiseret ved oprettelse af PR. Det er super effektivt, da det sommetider kan tage tid at køre samtlige tests i en given kodebase, men på denne måde ikke forhindrer udvikleren i at starte på andre opgaver imens checks'ene udføres.

![](https://i.imgur.com/LnqLHzF.png)

Der findes i øvrigt CI tools til automatisk generering af changelog og semantic version, fx [denne til CircleCI](https://circleci.com/developer/orbs/orb/payfit/semantic-versioning).

## Git hooks
Det er muligt at køre forskellige kommandoer automatiseret ved hvert commit. Det kan fx være linters som sikrer at koden er formateret korrekt jf vores konventioner. Disse kan gå så vidt som til at forhindre en udvikler i at push'e ændringer hvis en eller anden regel ikke er overholdt. Det kan selvfølgelig være meget rart, da man derved sikrer at der bliver taget stilling til kvaliteten af den kode man ønsker at push'e, men omvendt kan det også være direkte uhensigtsmæssigt hvis der ikke findes en måde at omgå disse checks på i de tilfælde hvor det har højere prioritet at få en ændring igennem med det samme.

Eksempler på tools der kan integreres med sådanne hooks er [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) og [phpmd](https://phpmd.org/).

## Automatisk opdatering af dependencies
Et tool som fx [Dependabot](https://dependabot.com/php/) kan hjælpe med at holde kodebasen opdateret for såvidt angår dependencies. Den opretter simpelthen PR's med forslag til opdatering af de anvendte pakker som er opdateret i forhold til de versioner som refereres i koden. Virker både til PHP og JavaScript (o.m.a.).

## Tools
* Changelog og versionering: https://github.com/xotahal/fastlane-plugin-semantic_release
* Eller vores egen "weka": https://github.com/drdk/weka

Se flere nederst på [https://www.conventionalcommits.org/en/v1.0.0/](https://www.conventionalcommits.org/en/v1.0.0/)

# Mit forslag
På baggrund af alt hvad jeg har læst, i kombination med det kendskab jeg har til vores eksisterende procedurer samt vores driftplatforme, kommer her et forslag med udgangspunkt i GitHub-Flow med et minimum af branches:
* Implementer ændringer i feature branches som branches fra `master`
  * Anvend conventional commits (Angular style)
* Opret PR så tidligt som muligt så andre udviklere kan kommentere på ændringer
  * Sæt CI op til at køre automatiserede tests mm ved hvert push til PR
* Merge `master` ind i feature branch jævnligt og fix evt merge conflicts
* Deploy feature branch til preprod når ændringerne er reviewed og checks er kørt fejlfrit[^1]
* Lav release branch fra master
* Merge de ønskede features ind i release branch'en
* Hold release branch'en opdateret ved at merge master ind jævnligt
* Deploy release branch til testmiljøer
* Merge til `master` når ændringerne er testet tilfredsstillende
  * Sæt CI op til at opdatere version og changelog ved merge til master
* Deploy `master` til prod

![](https://i.imgur.com/4xCEvrT.png)

# Noter
[^1]: Deploy fra feature branch kan evt udelades og i stedet gennemføres via release branch'en.