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

En trygg arbeidsflyt fra start til slutt

Modul 5: Verktøykassen · 15 min

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

Etter leksjonen kan du

  • gjennomføre en hel dag i et team: oppdatere main, jobbe på en branch, lese diffen, committe og pushe anvende
  • håndtere en avvist push ved å hente, integrere og pushe igjen, uten --force anvende
  • forklare hvorfor rebase er trygt for commits bare du har, men ikke for commits du allerede har delt med andre forstå
  • gjøre et risikabelt steg reversibelt: sjekke status og hvor fersk origin/main er, og lage en branch der du står før du flytter en branch anvende

Forstå: Løkka du gjentar hver dag

Før en kommando som endrer noe, spør deg selv: hvor står jeg, hva sier git status, og hva vet jeg egentlig om origin? I figuren har Ada pushet en ny commit. Din origin/main vet ikke om den før du henter.

Dagen starter med å oppdatere main. Så lager du en branch for oppgaven, gjør små commits og leser diffen før hver av dem.

Push branchen din tidlig. Da finnes det en kopi på serveren, og andre kan se arbeidet og gi tilbakemelding. Når den er ferdig, integrerer du den i main og pusher main.

Noen ganger avviser serveren pushen din. Da har noen andre pushet først, her Ada med commit D, og din commit E er ikke en fortsettelse av serverens historikk. Avvisningen er informasjon, ikke noe som skal tvinges bort.

Svaret er alltid det samme: hent, integrer og push igjen. git pull --rebase henter Adas commit og spiller din upushede commit E av på toppen av den. Kopien får en ny ID, og pushen blir en vanlig fast-forward.

Rebase bare commits som ingen andre har. Og bruk aldri --force på en delt branch for å komme forbi en avvisning, for da forsvinner andres commits fra branchen på serveren. Må du publisere omskrevet historikk på din egen branch, avtal det og bruk --force-with-lease.

Ta med deg denne sjekklista. Før en kommando som endrer noe, spør du: Hvor står jeg? Hva ligger i de tre områdene? Hvor fersk er origin/main? Og hvordan kommer jeg tilbake? Er du usikker på det siste, lager du først en branch der du står.

Se demo: Morgen: fra oppdatert main til publisert branch

Ny dag. Ada pushet en commit i går kveld. Før vi begynner, oppdaterer vi main. Vi har ingen egne commits her. Hva gjør git pull --rebase da?

$ git pull --rebase

Oppgaven i dag er en kontaktside. Den får sin egen branch.

$ git switch -c contact-page

Vi skriver kontaktsiden. Én liten, sammenhengende endring.

$ echo "Email: team@example.com" > contact.txt

Vi legger filen klar for commit.

$ git add contact.txt

Før commit leser vi nøyaktig det som skal inn. git diff --staged viser staging-området mot siste commit. Her oppdager du skrivefeil, hemmeligheter og filer som ikke hører hjemme.

$ git diff --staged

Diffen er som vi ville, så vi committer.

$ git commit -m "Add contact page"

Vi pusher branchen og setter upstream med -u. Se grafen: origin/contact-page dukker opp. Serveren har en kopi, og Ada kan se arbeidet.

$ git push -u origin contact-page

Oppgaver

  1. Oppdater main med det som ligger på origin.
  2. Lag og bytt til en branch contact-page.
  3. Les nøyaktig det som blir med i neste commit.
  4. Commit endringen med en beskrivende melding.
  5. Publiser branchen din på origin, med upstream.

Se demo: Ettermiddag: avvist push og integrasjon

Vi står på contact-page og legger til et telefonnummer i en ny commit. Det vi ikke vet, er at Ada har pushet en commit til den samme branchen.

$ echo "Phone: 555 0100" >> contact.txt && git commit -am "Add phone number"

Vi prøver å pushe. Hva svarer serveren?

$ git push

Vi henter Adas commit og spiller vår upushede commit oppå den. Det er trygt, fordi ingen andre har sett commiten vår ennå. I grafen får den en ny ID og ligger nå etter Adas.

$ git pull --rebase

Nå er historikken vår en fortsettelse av serverens, og pushen går gjennom uten tvang.

$ git push

Kontaktsiden er ferdig og skal inn i main. Vi bytter dit.

$ git switch main

Hent før du integrerer. Her har ingen pushet til main, så Git sier at alt er oppdatert. Det vet vi først nå.

$ git pull --rebase

main er en forfar til contact-page, så merge blir en fast-forward, og main flytter seg fram til den nyeste commiten. I et team med beskyttet main gjør vertstjenesten dette steget når pull requesten merges, med strategien teamet har valgt.

$ git merge contact-page

Til slutt pusher vi main. I grafen står main, origin/main og origin/contact-page på samme commit som contact-page. Ingen force, og ikke noe arbeid er tapt.

$ git push

Oppgaver

  1. Prøv å pushe commiten din, og les hva serveren svarer.
  2. Hent Adas arbeid og legg din upushede commit oppå det.
  3. Push branchen igjen.
  4. Sjekk at main er oppdatert med origin før du integrerer.
  5. Integrer contact-page i main.
  6. Publiser main.

Øv: Overfør: en rotete morgen

I går committet du et FAQ-utkast rett på main, og det er ikke pushet. Ada har pushet til main siden du hentet sist. Rydd opp og lever, med alt du har lært. Etterpå er du klar for sluttoppgaven, Fra solo til team.

Oppgaver

  1. Flytt FAQ-commiten over på en ny branch faq, og sett main tilbake slik at den ikke har noen upushede commits.
  2. Publiser faq på origin, så det finnes en kopi på serveren.
  3. Få faq inn i main på origin. Ada har pushet til main i mellomtiden. Ikke overskriv arbeidet hennes, og ikke bruk force.

Sjekk deg selv: Hent det fram igjen

git push blir avvist med beskjeden «fetch first». Hva gjør du?

  • git push --force, for det er jo min commit
  • Hent, integrer det nye og push igjen
  • Slett klonen og klon på nytt

Du står på en feature-branch og kjører git pull --rebase origin main. Når er det trygt?

  • Når commitene på branchen bare finnes på maskinen din
  • Alltid, for den rører bare commits som ikke er på main ennå
  • Bare når ingen har pushet til main siden du hentet sist

Du har kjørt git add. Hvilken kommando viser nøyaktig det som blir med i neste commit?

  • git diff
  • git diff --staged
  • git log -p

Grafen i verktøyet ditt ser ryddig ut. Er det nok til å pushe trygt?

  • Ja, grafen viser hele tilstanden
  • Nei. Sjekk også status, og hent først, for origin/main kan være utdatert
  • Ja, så lenge git status sier «up to date with origin/main»

Repetisjon fra «Angre delt historikk»: I går pushet du en commit til main som ødela bygget. Ada har allerede hentet den. Hvordan angrer du den?

  • git reset --hard HEAD~1 og så git push --force-with-lease
  • git restore ., som tar deg tilbake til før commiten
  • git revert på commiten, og så en vanlig git push

Vanlige misforståelser

  • «En avvist push er en feil som må tvinges gjennom.» Avvisningen beskytter andres commits. Hent, integrer og push igjen.
  • «git pull --rebase er alltid trygt.» Det skriver om dine lokale commits som upstream ikke har. Har du allerede delt dem, for eksempel pushet dem til en annen branch, får andre to versjoner av det samme arbeidet.
  • «En ryddig graf betyr at alt er i orden.» Grafen viser ikke ucommittede endringer, og origin/main er bare så fersk som siste fetch.

Les mer

Fire spørsmål før hver kommando som endrer noe

  1. Hvor står jeg? Hvilket repository, hvilken branch, er HEAD løsrevet? Den første linjen fra git status -sb svarer.
  2. Hva ligger i de tre områdene? Hva er endret, hva er staget, hva er usporet? En ryddig graf viser ikke ucommittet arbeid.
  3. Hva vet jeg egentlig om origin? origin/main er bare så fersk som siste fetch. Kjør git fetch før du bestemmer noe som avhenger av serveren.
  4. Hva vil kommandoen endre, og hvordan kommer jeg tilbake? Innebærer svaret å flytte en branch eller skrive om historikk, lager du først en branch der du står: git branch backup-before-rebase. Det koster ingenting og holder den committede historikken innen rekkevidde. Ucommittet arbeid sikrer du først, med en commit eller en stash.

Den daglige løkka

git switch main
git pull --rebase
git switch -c contact-page
git add contact.txt
git diff --staged
git commit
git push -u origin contact-page

Hold commitene små og sammenhengende: én grunn per commit. Skriv meldingene slik «Gode commits» beskriver, og les git diff --staged før hver commit; det er der du fanger feilsøkingsutskrifter, hemmeligheter og filer som ikke hører hjemme. Push branchen tidlig, så arbeidet finnes flere steder og andre kan gi tilbakemelding. Før du integrerer, oppdaterer du igjen og tester det samlede resultatet. I et team med beskyttet main skjer selve integrasjonen gjennom en pull request som noen har reviewet; uten det merger du lokalt og pusher main uten tvang.

En avvist push er informasjon

Når serveren avviser en push, beskytter den commits du ikke har:

$ git push
To ../origin.git
 ! [rejected]        contact-page -> contact-page (fetch first)
error: failed to push some refs to '../origin.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
...

«fetch first» betyr at serveren har commits du ikke engang har hentet. Har du hentet, men ikke integrert, står det «non-fast-forward» i stedet. Svaret er det samme: hent, se hva som kom med git log --oneline HEAD..origin/contact-page, integrer med git pull --rebase (for dine egne upushede commits) eller git pull --no-rebase (for å merge), kjør testene, og push igjen. Bruk aldri --force for å komme forbi denne meldingen på en delt branch. Har du skrevet om din egen branch og må publisere den, avtal det og bruk git push --force-with-lease; svakhetene ved den står i «Rebase». Force-push aldri main.

Vis at det faktisk kom fram

«Det virker hos meg» og «jeg har pushet» er påstander. Støtt dem med bevis:

$ git rev-parse HEAD
59c03df2da960ea31603edf622cfc25bfa0584c3
$ git ls-remote origin refs/heads/contact-page
59c03df2da960ea31603edf622cfc25bfa0584c3    refs/heads/contact-page

Samme ID lokalt og på serveren beviser at commiten du testet, er den som ble publisert. git log --oneline --graph --decorate --all viser historikken rundt den, og git status at ingenting er ucommittet.

Mal for en teamavtale

Kopier dette inn i CONTRIBUTING.md og fyll det ut sammen. Poenget er ikke de konkrete svarene, men at alle kjenner dem.

Brancher

  • main kan alltid releases. Ingen committer eller force-pusher direkte til main.
  • Én branch per oppgave, navngitt type/kort-beskrivelse, f.eks. feature/contact-page.

Commits

  • Små og sammenhengende. Emne <= 50 tegn, imperativ. Brødteksten forklarer hvorfor.
  • Aldri commit hemmeligheter, byggeresultater eller personlige editorfiler (.gitignore).

Integrasjon

  • Oppdater main og kjør testene før integrasjon.
  • Review: minst én annen person leser diffen før merge.
  • Strategi: rebase egne upushede commits; integrer feature-brancher på én avtalt måte (merge-commit, squash eller rebase).

Delt historikk

  • Skriv aldri om commits andre har. Angre delte commits med git revert. Force bare på egen branch, med --force-with-lease, etter å ha sagt fra til andre som bruker den.

Når noe går galt

  • Stopp. Kjør git status og git log. Lag en backup-branch før du eksperimenterer. Commits som ser tapt ut, finner du som regel i git reflog.
  • Spør i teamkanalen før en kommando du ikke kan forklare.

Neste: sluttoppgaven

Neste leksjon er sluttoppgaven. Der jobber du uten demo: samarbeid gjennom en felles remote, løs en konflikt, begrunn en merge eller en rebase, rett opp en feil og lever med bevis. Bruk de fire spørsmålene over i hvert steg.

Offisiell dokumentasjon