Beskytt master med en Git-hook

Teodor Heggelund

I Github kan man beskytte master-branchen ved å kreve pull request før merge.

Du kan også beskytte master-branchen fra din egen datamaskin. Fortsett å lese for å lære hvordan.

Brent barn … søker flammene men tar på vernebriller neste gang?

I desember pushet jeg uferdig kode til master i en kodebase jeg jobbet i. I commit-loggen finner du følgende:

51714f32 Revert "explore"
b736d6c3 explore

Det var slett ikke meningen å pushe b736d6c3 på master.

Hvordan kan jeg sørge for at det aldri skjer igjen?

Git har en krok du kan bruke til å kjøre din egen kode før hver commit

Her er et shell-script-program som alltid sier OK:

#!/bin/sh

exit 0

Her er et shell-script-program som alltid sier nei:

#!/bin/sh

exit 1

Jeg tror "0 er OK og ikke-null er ikke-OK" er arv fra Unix. Kanskje noen andre kan utdype? Jeg vet vi har solid Unix-kompetanse på huset.

Nåvel. La oss gjøre noe faktisk interessant. Her er et shell-program som kjører testene i et javascript-prosjekt:

#!/bin/sh

npm run test

Dette fungerer fordi scriptet returnerer koden som det siste programmet returnerte. npm følger de samme konvensjonene som over. Returkode 0 er OK, returkode ikke-null er ikke-OK.

Hvis du nå setter at Git sin pre-commit hook skal være shell-scriptet ditt som kjører testene, vil du ikke få lov til å commite med mindre testene er grønne. (Du vil heller ikke få committe hvis du er i en mappe der npm ikke har noen test å kjøre, men det er en annen sak.)

Er det en god ting å sette opp? Tja. Jeg har ikke noe sånt når jeg koder. Men prøv det gjerne. Git hooks er kjempenyttige, og måten å lære å bruke Git hooks er å prøve.

Et shell-program som sjekker om du er på master

Jeg har skrevet dette programmet:

#!/bin/sh

### Ensure no commits directly on master

# Blacklist - only for repos that are not teod.
if [ "teod" != "$(basename $(git rev-parse --show-toplevel))" ]; then
  branch=$(git rev-parse --abbrev-ref HEAD)

  if [ "$branch" = "master" ]; then
    echo "You can't commit directly to master branch"
    exit 1
  fi
fi

La oss gå gjennom linje for linje.

  • #!/bin/sh sier at dette er et Bourne Shell-program. Bourne Shell ble laget på 70-tallet. I terminalen din bruker du sannsynligvis Bourne Again Shell også kjent som Bash, eller Z Shell, også kjent som Zsh. Bash og Zsh er bakoverkomtatible med Bourne shell. Det betyr at #!/bin/sh funker på de fleste moderne Linux-maskiner og Mac-maskiner.

  • ### Ensure no commits directly on master er en kommentar! Jeg vet egentlig ikke hvorfor jeg brukte tre #-tegn her. Ett tegn er nok. # er for kommentarer, som i Python. Eller, # er sannsynligvis for kommentarer i Python fordi Python gjorde det samme som Bourne Shell.

  • if [ "teod" != "$(basename $(git rev-parse --show-toplevel))" ]; then
      ...
    fi
    

    er en if som sjekker at git repo-mappen ikke heter nøyaktig "teod". Det er fordi jeg har et repo som heter amedia/teod som jeg vil comitte til master på.

  • branch=$(git rev-parse --abbrev-ref HEAD) gir meg navnet på git-branchen jeg er på nå.

  • if [ "$branch" = "master" ]; then
      echo "You can't commit directly to master branch"
      exit 1
    fi
    

    ... og hvis vi er på master, si "du får ikke comitte nå", og returner 1, "avbryt!"

"Men … hvordan installerer jeg en Git-hook?"

"Men … det er jo forskjell på pre-commit hooks og post-commit hooks?"

Ja, det er det! Jeg skulle kanskje sagt pre-commit hook hver gang jeg har sagt hook i dag. Jeg droppet det, fordi jeg ville fokusere på noe annet. Når du skal installere denne må du installere den som en pre-commit hook. Hvis du installerer den som en post-commit hook, vil du først comitte, så kjøre testen, så vil den feile. Ikke det vi ønsket!