Sluttoppgave: fra solo til team
Den interaktive leksjonen trenger JavaScript. Teksten under er hele leksjonen.
Etter leksjonen kan du
- gjennomføre hele løypa fra feature-branch til publisert main i ekte Git, uten demo anvende
- velge merge eller rebase ut fra om branchen er delt, og fremprovosere, avbryte og løse en konflikt vurdere
- velge revert på delt historikk og reset bare på en disponibel branch, og redde arbeid med reflog vurdere
- publisere uten å overskrive en kollega, også etter en avvist push anvende
Forstå: Oppdraget
Dette er sluttoppgaven. Ingen demo denne gangen. Du tar en liten feature på to commits fra en feature-branch inn i teamets main, mens Ada jobber i sin egen klone. Alt skjer lokalt, med origin som et bare repository.
Ada publiserer noe på main underveis. Du henter, integrerer med merge eller rebase, og møter en konflikt som du først avbryter og så løser. Til slutt havner alt i main i origin.
Så gjør du en bevisst feil på delt historikk og angrer den med en ny commit, ikke ved å flytte main bakover. Reset og reflog øver du bare på en disponibel branch som ingen andre har.
Du er ferdig når arbeidsmappen er ren, ingen konfliktmarkører er igjen, og ingen av Adas commits er overskrevet. Du skal kunne forklare hver kommando du brukte.
Kurset sjekker resultatet av hver oppgave, ikke ordlyden, så alle riktige veier godkjennes. Bruker du --force eller et annet destruktivt valg som oppgaven ikke trenger, må du starte sluttoppgaven på nytt fra første oppgave. Sjekklisten står under Les mer.
Øv: Leveransen, steg for steg
Du og Ada har hver deres klone av origin, og alle står på samme commit. Oppgavene bygger på hverandre i rekkefølge. Noen gjør du som Ada; terminalen bytter til klonen hennes.
Oppgaver
- Lag en feature-branch som heter
feature, og lag minst to sammenhengende commits på den. Se på den stagede diffen før hver commit. La README.md være i fred, den trenger du senere. Arbeidsmappen skal være ren etterpå. - Som Ada: publiser en annen endring på main. Lag en ny fil, for eksempel
schedule.txt, commit den og push. - Tilbake hos deg: vis hvor main og origin/main peker, hent nytt fra origin, og vis det samme igjen. Din egen main skal ikke flytte seg.
- Integrer Adas commit i
feature, med merge eller rebase. Velg selv, og noter hvilke ID-er som er nye. - Som Ada: skriv om den første linjen i
README.mdpå main, commit og publiser. - Hos deg, på feature: skriv om den samme første linjen i
README.mdpå en annen måte enn Ada, og commit. Ikke hent Adas endring ennå. - Hent og integrer Adas nye commit i feature. Det stopper med en konflikt. Stopp der og se på
git status. - Avbryt integrasjonen, og bekreft at feature er nøyaktig som før, uten Adas nye commit.
- Gjør integrasjonen på nytt, og løs konflikten med et sluttinnhold du kan begrunne. Fjern markørene og fullfør.
- Integrer feature i main og publiser main til origin.
- Lag en bevisst feil på main: commit en fil
debug.logsom ikke hører hjemme i repositoryet, og push den. Nå er feilen i delt historikk. - Angre feilen på en måte som passer delt historikk, og publiser rettelsen. Den dårlige commiten skal fortsatt finnes i historikken.
- Lag en disponibel branch
experimentfra main, lag én commit på den, og kast commiten igjen på den måten som passer for en branch bare du har, slik at branchen står på main igjen. - Du ombestemmer deg. Finn den bortkastede commiten i reflog, bevar den i en branch som heter
rescue, og sjekk innholdet. - Som Ada: oppdater main fra origin, lag én commit til og publiser den.
- Siste leveranse: på main, legg til
CHANGELOG.mdi en commit og publiser den til origin uten å overskrive Adas arbeid. Den første pushen blir avvist.
Sjekk deg selv: Begrunn valgene dine
Du finner to dårlige commits. X ligger på branchen experiment, som bare du har. Y ligger på main i origin, og Ada har allerede pullet den. Hva gjør du?
- Reset begge, og publiser main med
git push --force-with-lease - Reset
experimentforbi X, og reverter Y med en ny commit - Reset begge, og push main som vanlig
Pushen din til main blir avvist. Du har nettopp kjørt git fetch. En medstudent foreslår git push --force-with-lease fordi den er trygg. Hva skjer?
- Den nekter, fordi origin har flyttet seg
- Den merger Adas commit inn automatisk
- Den lykkes, og Adas commit forsvinner fra main i origin
I går pushet du feature så Ada kunne se på den, og hun har hentet den. Nå har main fått nye commits. Hvordan tar du dem inn i feature?
- Rebase på origin/main og force-push
feature - Merge origin/main inn i
featureog push som vanlig - Cherry-pick de nye commitene fra main over på
feature
Du har kjørt git reset --hard HEAD~1 på experiment og vil likevel beholde commiten. Hva sikrer den?
- Ingenting trengs: reflog tar vare på den for alltid
- En branch som peker på den, for eksempel
git branch rescue HEAD@{1} git status, som viser commits som er resatt bort
Vanlige misforståelser
- «En avvist push løser jeg med --force-with-lease, den er jo trygg.» Etter en fetch stemmer leasen, og kollegaens commit forsvinner likevel.
- «Reset og revert gjør det samme.» Reset flytter en branch bakover; revert legger til en ny commit som opphever en gammel. Bare revert passer på delt historikk.
- «Reflog er en backup.» Den er lokal og utløper. Lag en branch for det du vil beholde.
Les mer
Oppdraget
Ta en liten feature på to commits fra din egen maskin inn i teamets felles historikk, mens Ada jobber i sin egen klone samtidig. Alt kjører lokalt: origin er et bare repository i /course/origin.git, Adas klone er /course/ada, og du trenger ingen konto hos en hostingtjeneste. Dette er en egenkontroll, ikke en eksamen med karakter.
Du leverer sju ting:
- En feature-branch med minst to sammenhengende commits. Se på
git diff --stagedfør hver commit. - Ada publiserer en annen endring på
main. Vis hvor dinmainogorigin/mainpeker før og ettergit fetch. - Integrer Adas arbeid med merge eller rebase, og begrunn valget. Noter foreldrene, og hvilke ID-er som er nye.
- Fremprovoser en konflikt i en sporet tekstfil. Avbryt én gang, gjenta så og løs den med et innhold du kan begrunne.
- Publiser en bevisst feil på
main, og angre den på en måte som passer delt historikk. Forklar hvorfor en reset ikke ville vært det samme. - På en egen, disponibel branch: reset bort en commit, finn den igjen med
git reflogog bevar den i en branch som heterrescue. - Publiser bare til den lokale origin, uten å overskrive Adas arbeid, også når pushen din blir avvist.
Akseptansekriterier
- Arbeidsmappen er ren når du er ferdig, eller gjenstående endringer er forklart.
- Ingen konfliktmarkører er igjen, og en relevant sjekk av oppførselen passerer.
- Ingen kollegas arbeid er overskrevet for å komme forbi en avvist push: ingen
--force, ingen--force-with-leasepåmain. - Du kan forklare hver kommando uten å peke på en knapp i et GUI.
Vis bevisene dine
Disse kommandoene bare leser, og de gjør historien synlig. Kjør dem ofte; ingen av dem endrer noe.
| Spørsmål | Kommando |
|---|---|
| Hvor står jeg, og er noe ucommittet? | git status |
| Hva vil neste commit inneholde? | git diff --staged |
| Hvordan ser hele historikken ut? | git log --oneline --graph --all |
| Hvor langt foran eller bak er hver branch? | git branch -vv |
| Hvem er foreldrene til en commit? | git rev-list --parents -n 1 HEAD |
| Hvor pekte branchen min tidligere? | git reflog |
| Hva har origin som jeg ikke har integrert? | git log --oneline main..origin/main |
En merge-commit har to foreldre, så git rev-list --parents -n 1 HEAD skriver tre ID-er: commiten selv og begge foreldrene. Etter en rebase sammenligner du ID-ene fra git log --oneline med dem du noterte før: commitene som ble spilt på nytt, har nye ID-er selv om meldingene er de samme.
Valg du må kunne begrunne
Merge eller rebase? Rebase feature-branchen bare mens commitene finnes på din maskin alene; resultatet er en rett linje som er lett å reviewe. Når en branch er delt, merger du i stedet, for en rebase ville gitt kollegaene kopier av commits de allerede har.
Revert, ikke reset, på delt historikk. git revert legger til en ny commit som opphever endringen, så alle som allerede har den dårlige commiten, bare kan pulle rettelsen. Å resette main og pushe ville krevd en tvungen push, fjernet commits andre har bygget på, og latt klonene deres være uenige med origin.
Aldri tving deg forbi en avvisning. En avvist push betyr at origin har commits du ikke har integrert. Løsningen er hent, integrer, test og push. --force-with-lease hjelper ikke her: når du har hentet, stemmer leasen, og Adas commit ville forsvunnet likevel.
Reset bare der du er alene. En hard reset er akseptabel på en disponibel branch som ingen andre har. Før du rydder noe bort, sørg for at commiten du vil ha, kan nås fra en branch; reflog er et lokalt, midlertidig sikkerhetsnett, ikke en backup.
Sjekkliste for egenvurdering
Gå ærlig gjennom hver linje før du sier deg ferdig.
- Feature-branchen min har minst to commits, hver med ett formål og en melding som sier hvorfor.
- Jeg kan si hvor
main,origin/mainog main i origin pekte før og etter fetch. - Jeg kan navngi foreldrene til integrasjonscommiten min, eller de nye ID-ene rebasen min laget.
- Jeg avbrøt den første konflikten og så at branchen var nøyaktig som før.
- Konfliktløsningen min er et bevisst valg, ikke bare én side, og ingen markører er igjen.
- Den dårlige commiten finnes fortsatt i historikken til origin, etterfulgt av en commit som opphever den.
rescue-branchen peker på commiten jeg resatte bort, og jeg har sjekket innholdet.- Adas siste commit er en forfar til
maini origin. git statuser ren.
Medstudentreview
Bytt logger med en medstudent. Den som reviewer, skal kunne gjenskape hovedforløpet ditt bare fra git log --oneline --graph --all og git reflog. Spør hverandre:
- Hvilken commit laget Ada, og hvordan kom den inn i branchen din?
- Hvorfor valgte du merge eller rebase, og hva gjorde det med ID-ene?
- Hvor er konfliktløsningen, og hvorfor er sluttinnholdet riktig?
- Hvilken kommando angret feilen, og hvorfor ville en reset vært feil?
- Hva ville skjedd om du hadde brukt
--forcetil slutt?
Gi hverandre ett konkret forbedringsforslag hver. Får dere ulike resultater av de samme stegene, sammenlign branch, HEAD, konfigurasjon og arbeidsfiler før dere konkluderer med at Git er tilfeldig. Det er det aldri.
Offisiell dokumentasjon
- gitworkflows
- git revert, git reset og git reflog
- git push, særlig notatet om fast-forwards
Per-Arne's Git Good!