Meny for Per-Arne's Git Good!
Fag og prosjekt Per-Arne's Git Good!

Teamarbeid: feature-brancher, pull requests og avtaler

Modul 3: Samarbeid · 12 min

Den interaktive leksjonen trenger JavaScript. Teksten under er hele leksjonen.

Etter leksjonen kan du

  • lage en feature-branch, publisere den med git push -u, og forklare hvorfor det ikke endrer main anvende
  • skille stegene Git gjør fra det hostingtjenesten legger til: pull requests, branchbeskyttelse og CI forstå
  • reviewe en publisert branch med git log main..origin/greeting og git diff main...origin/greeting, og deretter merge den og publisere main anvende

Forstå: Fra branch til main, via review

I et team er main den felles versjonen som alle bygger på. Den skal alltid virke. Derfor får hver endring sin egen feature-branch. Du lager branchen greeting fra main og committer der. Main og origin er urørt.

git push -u origin greeting publiserer branchen. Origin får en branch som heter greeting, og din greeting får origin/greeting som upstream. Main i origin er den samme som før. Å publisere er ikke å integrere.

Nå åpner du en pull request i hostingtjenesten. Den sier: vær så snill og se over greeting, og merge den inn i main. GitLab kaller det en merge request. Git selv vet ingenting om den. Tjenesten legger til diff, kommentarer, godkjenning og testresultater rundt branchen.

Den som reviewer, henter først og stiller to spørsmål. Hvilke commits er nye? git log main..origin/greeting viser commits på branchen som main ikke har. Hva er endringen? git diff main...origin/greeting viser endringen siden branchen skilte lag med main.

Når endringen er godkjent, merges branchen inn i main, ofte med en merge-commit. Merge-knappen i hostingtjenesten gjør det rett i origin. Nå inneholder main i origin commiten din. Din egen main får den neste gang du puller.

Hold branchene korte: én avgrenset endring, merget i løpet av en dag eller to. Jo lenger en branch lever, jo mer flytter main seg under den, og jo større blir konfliktene. Etter merge sletter dere branchen i origin med git push origin --delete greeting.

Teamet avtaler også regler: ingen pusher rett til main, hver endring trenger en godkjent review, og CI, testene tjenesten kjører på hver pull request, må være grønn. Git selv håndhever ingenting av dette. Det gjør hostingtjenesten, med branchbeskyttelse på main.

Se demo: Du lager en branch, Ada reviewer og merger

Du og Ada har hver deres klone, og alle er enige om main. Du starter en ny endring på en egen branch som heter greeting.

$ git switch -c greeting

Vi gjør en liten, avgrenset endring og committer den. Bare greeting flytter seg.

$ echo "Hello, team!" > greeting.txt && git add greeting.txt && git commit -m "Add team greeting"

Nå publiserer vi branchen. Se grafen: greeting dukker opp inne i origin, men main i origin står stille.

$ git push -u origin greeting

På hostingtjenesten ville du nå åpnet en pull request. Her later vi som om Ada har fått den. Hun reviewer, og først henter hun.

$ git fetch

Hvilke commits vil branchen legge til i main? To prikker betyr: nåbar fra origin/greeting, men ikke fra main. Her er det én commit.

$ git log --oneline main..origin/greeting

Hva er selve endringen? Tre prikker sammenligner med merge-basen, punktet der branchen skilte lag med main. Ada ser bare det som er gjort på branchen.

$ git diff main...origin/greeting

Ada godkjenner og merger. Her gjør hun lokalt det merge-knappen i hostingtjenesten ellers gjør i origin. --no-ff lager en merge-commit selv når en fast-forward hadde holdt, og --no-edit beholder den foreslåtte meldingen.

$ git merge --no-ff --no-edit origin/greeting

Til slutt pusher Ada main. Nå er endringen integrert i origin. Din main står fortsatt der den sto, til du puller.

$ git push

Oppgaver

  1. Start en ny branch som heter greeting, og gå over på den.
  2. Publiser branchen til origin, og la den følge origin/greeting.
  3. Som Ada: last ned den nye branchen fra origin.
  4. Som Ada: list commitene som branchen vil legge til i main.
  5. Som Ada: vis endringen branchen gjør siden den skilte lag med main.
  6. Som Ada: merge den reviewede branchen inn i main med en merge-commit.
  7. Som Ada: publiser den mergede main.

Øv: Overfør: du reviewer Adas branch

Rollene er byttet. Ada har publisert branchen docs og ber deg om review. I mellomtiden har main fått en ny commit. Fordi linjene har delt seg, blir det en merge-commit også uten --no-ff.

Oppgaver

  1. Få Adas branch inn på maskinen din, og se hvilke commits den vil legge til i main og hva den endrer.
  2. Godkjenn: merge docs inn i main med en merge-commit, og publiser main.

Sjekk deg selv: Hent det fram igjen

Hva er en pull request?

  • En spesiell type commit i Git
  • Et annet navn for git pull
  • En forespørsel i hostingtjenesten om å reviewe en branch og merge den

Du reviewer Adas branch docs. Etter git fetch skriver git log --oneline main..origin/docs ingenting. Hva betyr det?

  • Branchen docs har ingen commits
  • Alle commitene på origin/docs er allerede i main, så det er ingenting nytt å reviewe
  • At main ikke har fått nye commits siden docs ble laget

CI er grønn på en pull request. Hva beviser det?

  • At endringen er riktig og kan merges uten review
  • At testene som kjørte, passerte på akkurat den versjonen
  • At en kollega har godkjent endringen

Repetisjon fra modul 2: main hadde ti commits da du lagde greeting. Siden har begge branchene fått nye commits. Hva er merge-basen til main og greeting?

  • Den aller første commiten i repositoryet
  • Commiten main pekte på da greeting ble laget, den nyeste som begge har
  • Commiten main peker på akkurat nå

Vanlige misforståelser

  • «En pull request er en del av Git.» Den er en funksjon i hostingtjenesten. Git ser bare brancher og commits.
  • «Når jeg pusher branchen min, er arbeidet i main.» Å publisere en branch er ikke å integrere den. Main endrer seg først når noen merger.
  • «Grønn CI betyr at endringen er riktig.» Den viser bare at testene som kjørte, passerte på den versjonen.

Les mer

Én endring, fra start til slutt

En team-arbeidsflyt er et sett avtaler dere gjør før noen får en konflikt: hvor stor en endring får være, hvem som reviewer, hva testene må vise, og hvordan endringen kommer inn i main. En typisk løype for én endring ser slik ut:

git switch main
git pull --ff-only
git switch -c feature/usage
# rediger USAGE.md, stage den, og se nøyaktig hva du er i ferd med å lagre
git add USAGE.md
git diff --staged
git commit -m "Document local usage"
git push -u origin feature/usage

Deretter åpner du en pull request i hostingtjenesten. Git ser aldri pull requesten. Den er en side rundt branchen din med beskrivelse, diff, kommentarer, godkjenninger og testresultater. GitLab kaller det samme for en merge request.

Skriv en pull request som lar seg reviewe

Hold den liten: ett formål, helst noen hundre endrede linjer på det meste, reviewet i løpet av en dag eller to. En kort beskrivelse sparer reviewer for gjetting:

Problem:   New students do not know how to run the example.
Change:    Adds USAGE.md with the one command that starts it.
Behaviour: Before, README had no instructions. After, USAGE.md explains it.
Checked:   ran ./run-example.sh; it printed "OK" (exit status 0).

Skriv testen du faktisk kjørte og det faktiske resultatet, ikke «burde virke».

Review: hent, og still to spørsmål

Den som reviewer, henter først, holder main oppdatert med git pull --ff-only og sammenligner så branchen med main:

$ git log --oneline main..origin/greeting
f785ce9 Greet Ada by name
035b6f9 Add team greeting
$ git diff --stat main...origin/greeting
 greeting.txt | 2 ++
 1 file changed, 2 insertions(+)
Syntaks I git log I git diff
main..origin/greeting commits på branchen som main mangler forskjellen mellom de to tuppene, inkludert det som er endret på main
main...origin/greeting commits på én av sidene, men ikke begge bare branchens egen endring, målt fra merge-basen der den skilte lag med main

Til review bruker du altså to prikker med log og tre prikker med diff. For å kjøre koden sjekker du ut branchen lokalt med git switch greeting.

En nyttig review spør: gjør endringen det beskrivelsen lover? Mangler det tester for den nye oppførselen? Er noe risikabelt, som slettede filer, hemmeligheter eller endret konfigurasjon? Vil neste person forstå det? Kommenter koden, ikke personen, og si hvilke kommentarer som må fikses og hvilke som er forslag. Forfatteren svarer med nye commits på samme branch og en vanlig push. Hvis forfatteren i stedet rebaser branchen på en nyere main, skrives branchens historikk om, og oppdateringen krever git push --force-with-lease. Det er greit på din egen pull request-branch og aldri på main. Rebase og når --force-with-lease passer, kommer i leksjonen «Rebase» i modul 4.

Tre måter å integrere på

Merge-knappen tilbyr vanligvis tre strategier. De gir de samme filene på main og ulik historikk:

Strategi Lokal motpart Commits på main etterpå
Merge-commit git merge --no-ff feature alle commitene på branchen pluss en merge-commit med to foreldre
Squash git merge --squash feature og så git commit én ny commit med én forelder; branchens commits er ikke forfedre
Rebase og merge git rebase main på branchen, så fast-forward kopier av alle commitene på branchen, med nye ID-er, på en rett linje

git merge --squash forbereder den samlede endringen, men committer ikke:

$ git merge --squash origin/greeting
Updating 5dd6192..f785ce9
Fast-forward
Squash commit -- not updating HEAD
 greeting.txt | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 greeting.txt
$ git commit -m "Add team greeting (#12)"

Avtal én strategi. Merge-commits bevarer den sanne historien; squash holder main kort, men mister de enkelte stegene; rebase beholder stegene, men endrer ID-ene deres. Etter en squash, eller en rebase som merge-knappen gjør, er ikke branchens egne commits forfedre til main. Git ser da ikke branchen som merget, så slett den med omtanke.

Branchbeskyttelse og CI

Git håndhever ingen teamregler selv. Det gjør hostingtjenesten, med branchbeskyttelse på main: ingen direkte push, ingen tvungen push, ingen sletting, et påkrevd antall godkjenninger og påkrevde statussjekker. En lokal hook kan ikke håndheve en regel for alle, fordi hooks ikke klones og hvem som helst kan hoppe over dem.

CI (kontinuerlig integrasjon) kjører de avtalte sjekkene ved hver push til en pull request, ofte på resultatet av å merge den inn i nyeste main. Grønn CI beviser bare at akkurat de sjekkene passerte på akkurat den versjonen. Den beviser ikke at testene er gode nok, eller at endringen er det brukerne trenger. Derfor krever team både grønn CI og godkjent review.

Forks

I åpen kildekode pusher du ofte til en fork og åpner pull requesten derfra. Oppsettet med origin og upstream står i leksjonen «Remotes og clone».

Rydd opp etter merge

Slett branchen i remoten. Pushen fjerner også din egen origin/greeting:

$ git push origin --delete greeting
 - [deleted]         greeting
$ git branch -vv
* greeting f785ce9 [origin/greeting: gone] Greet Ada by name

I andre kloner, som Adas, står origin/greeting igjen til de kjører git fetch --prune. gone betyr at upstream ikke finnes lenger. Bytt bort og fjern den lokale branchen med git branch -d greeting. Git nekter hvis den ikke ser commitene som merget, og det skjer etter en squash; sjekk med git log main..greeting før du vurderer -D med stor D.

Offisiell dokumentasjon