En trygg arbeidsflyt fra start til slutt
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
--forceanvende - 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/mainer, 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
- Oppdater
mainmed det som ligger på origin. - Lag og bytt til en branch
contact-page. - Les nøyaktig det som blir med i neste commit.
- Commit endringen med en beskrivende melding.
- 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
- Prøv å pushe commiten din, og les hva serveren svarer.
- Hent Adas arbeid og legg din upushede commit oppå det.
- Push branchen igjen.
- Sjekk at
mainer oppdatert med origin før du integrerer. - Integrer
contact-pageimain. - 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
- Flytt FAQ-commiten over på en ny branch
faq, og settmaintilbake slik at den ikke har noen upushede commits. - Publiser
faqpå origin, så det finnes en kopi på serveren. - Få
faqinn imainpå origin. Ada har pushet tilmaini 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å
mainennå - Bare når ingen har pushet til
mainsiden du hentet sist
Du har kjørt git add. Hvilken kommando viser nøyaktig det som blir med i neste commit?
git diffgit diff --stagedgit 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/mainkan være utdatert - Ja, så lenge
git statussier «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~1og sågit push --force-with-leasegit restore ., som tar deg tilbake til før commitengit revertpå commiten, og så en vanliggit 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 --rebaseer 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/mainer bare så fersk som siste fetch.
Les mer
Fire spørsmål før hver kommando som endrer noe
- Hvor står jeg? Hvilket repository, hvilken branch, er HEAD løsrevet? Den første linjen fra
git status -sbsvarer. - Hva ligger i de tre områdene? Hva er endret, hva er staget, hva er usporet? En ryddig graf viser ikke ucommittet arbeid.
- Hva vet jeg egentlig om origin?
origin/mainer bare så fersk som siste fetch. Kjørgit fetchfør du bestemmer noe som avhenger av serveren. - 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
mainkan alltid releases. Ingen committer eller force-pusher direkte tilmain.- É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
mainog 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 statusoggit log. Lag en backup-branch før du eksperimenterer. Commits som ser tapt ut, finner du som regel igit 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.
Per-Arne's Git Good!