# Git

## Hva det er

Git er et distribuert versjonskontrollsystem: et program som registrerer tilstanden til et sett
filer som en kjede av øyeblikksbilder, slik at enhver tidligere tilstand kan ses på, sammenlignes
med nåtiden eller hentes tilbake. Prosjektet skriver navnet som Git og kommandoen som `git`, og
begge betegner det samme verktøyet.

Hvert øyeblikksbilde er en commit. En commit lagrer hvordan hver sporet fil så ut i det øyeblikket,
hvem som gjorde endringen og når, en melding som forklarer hvorfor, og en peker til den eller de
commitene som kom før. En fil git allerede har sett, lagres bare én gang: er filen uendret mellom to
commits, peker det nye øyeblikksbildet på kopien som allerede ligger på disken, i stedet for å
skrive den på nytt. Derfor tar en lang historikk langt mindre plass enn en full kopi per commit
ville gjort.

Alt inni er navngitt etter innholdet. Før git lagrer en fil, en katalogoversikt eller en commit,
regner den ut en sjekksum over bytene, i det klassiske formatet en SHA-1-hash skrevet som 40
heksadesimale tegn, og den sjekksummen blir objektets navn. Endrer du én enkelt byte, endres navnet
med den, og det samme gjør navnet på hver commit som er bygd oppå. Slik oppdager git skadde data, og
derfor peker en commit-id fortsatt på nøyaktig den samme koden mange år senere.

Distribuert betyr at hver kopi er komplett. Når du kloner et repo, får du hele historikken og ikke
bare de nyeste filene, så å lese loggen, sammenligne to versjoner eller lage en commit skjer på den
lokale disken uten at noen server er involvert. Å dele arbeid er et eget, bevisst steg: du pusher
commitene dine til en annen kopi, eller du henter commits fra en og fletter dem inn. Hvilken som
helst kopi kan fungere som server. I de fleste team spiller én avtalt kopi, ofte hos en
vertstjeneste, den rollen etter konvensjon og ikke fordi verktøyet krever det.

En arbeidsdag beveger seg gjennom tre steder. Arbeidstreet holder filene du redigerer.
Oppsamlingsområdet, også kalt indeksen, holder det den neste commiten skal inneholde, slik at du kan
committe en del av endringene og ta vare på resten til senere. Selve git-katalogen, `.git` øverst i
prosjektet, holder objektdatabasen og alle referansene. En gren er bare et flyttbart navn som peker
på én commit, og derfor går det på et øyeblikk å opprette en.

Git ble skrevet i 2005 av Linus Torvalds og miljøet rundt Linux-kjernen, etter at gratisstatusen til
BitKeeper, det proprietære verktøyet de hadde brukt, ble trukket tilbake. Målene de satte seg, var
fart, en enkel utforming, god støtte for tusenvis av parallelle grener, full distribusjon og evne
til å håndtere et prosjekt på størrelse med kjernen.

## Hvorfor det er viktig

Versjonskontroll svarer på spørsmålene som dukker opp så snart mer enn én person, eller én person
over mer enn en uke, rører de samme filene: hva som ble endret, når, av hvem og hvorfor. Holdes
svarene for hånd, lever de i hukommelsen, i filnavn som `final-v3` og i e-posttråder. Med git ligger
de ved siden av koden, festet til hver endring, der hvem som helst kan søke i dem.

Den distribuerte utformingen endrer hvordan et team jobber fra dag til dag. Hver klone holder hele
historikken, så ingen venter på en sentral server for å lese loggen eller committe, og når serveren
er nede, kan alle jobbe videre. Grener er billige, så hver funksjon, retting eller eksperiment kan
få sin egen, bli gjennomgått for seg og flettes inn når den er klar, mens hovedlinjen hele tiden
holder mål for levering.

Den samme utformingen gjør git forsiktig med data. Nesten hver operasjon legger bare til i
objektdatabasen, så arbeid som er committet, er vanskelig å miste: en gren som ble slettet ved en
feil, en rebase som gikk skjevt, eller en reset til feil commit kan som regel gjøres om.
Sikkerhetsnettet er refloggen, en lokal oversikt over hvor hver gren pekte og når. Som standard tas
den vare på i 90 dager for commits som fortsatt kan nås, og i 30 dager for dem som ikke kan det.

Git er også felles grunn under de fleste andre verktøyene i en leveransekjede. Forger, verktøy for
kodegjennomgang, byggepipelines, skript for produksjonssetting og statiske nettstedsgeneratorer
leser alle fra den, og det gjør historikken til en kilde til fakta langt utover koden: dagen en side
sist ble endret, commiten en utgivelse ble bygd fra, endringen en feil kom inn med.

## Slik ser det ut i praksis

Selskapets egen kode viser tre sider av dette.

Kildekoden lå tidligere hos en tredjeparts vertstjeneste. Nå ligger den på
[en git-server selskapet drifter på sin egen maskinvare](/nb/portfolio/deployed-the-companys-own-git-forge-121/):
én binærfil som styres av operativsystemet, valgt fordi den er SSH-først uten noe administrativt
webgrensesnitt. Hvert deklarerte repo er merket som privat, og forgen avviser både anonyme klienter
og klienter uten nøkkel. Git-kommandoene snakker med en SSH-lytter som bare er bundet til port 23231
på loopback-grensesnittet, og utenfra går veien via en hoppvert. Siden legger ikke skjul på prisen:
å drifte sin egen forge betyr å eie autentisering, tilgangskontroll, lagring og sikkerhetskopier i
tillegg.

Fullstendige kopier av historikken på flere maskiner er lette å forveksle med en sikkerhetskopi. Før
[krypterte sikkerhetskopier utenfor verten med en månedlig gjenopprettingsøvelse](/nb/portfolio/built-encrypted-backups-with-a-monthly-restore-drill-114/)
kom på plass, lå alt selskapet hadde, git-repoene, databasen og nettstedet, på én skyinstans der
leverandørens øyeblikksbilde var hele gjenopprettingsberedskapen. Det som kom i stedet, er bygd
annerledes enn en klone: et kryptert, deduplisert øyeblikksbilde som en systemd-timer sender til
lagring hos en annen leverandør, ryddet etter en oppbevaringsregel og sjekket for integritet, og en
øvelse som hver måned henter en kjent fil ut igjen og sammenligner den. Prøven på en
gjenopprettingsberedskap er en gjenoppretting som faktisk har kjørt, og samme hvor mange kloner som
ligger på bærbare maskiner, blir de aldri til én slik.

Historikken mater også selve nettstedet. [Nettstedets kolofon](/nb/credits/) skriver at
[W3C Feed Validator](https://validator.w3.org/feed/) advarer om at de fleste oppføringene i feedene
har samme endringsdato, og at advarselen er riktig: datoene kommer fra git-historikken, og de fleste
av disse sidene ble faktisk skrevet i en håndfull commits. Nettstedet viser heller advarselen enn å
finne på en dato. Historikken forteller hva som skjedde, også at mye av det skjedde på én gang.

Én kommando leser et slikt faktum tilbake. Denne skriver ut den korte identifikatoren, commitdatoen
i ISO 8601-form og emnelinjen til den siste commiten som rørte én bestemt fil:

```sh
git log -1 --format='%h %cI %s' -- README.md
```

## Hvor det går galt

- **En hemmelighet som er committet én gang, blir liggende i historikken.** Sletter du filen i neste
  commit, forsvinner den fra det siste øyeblikksbildet, men den blir liggende i det forrige, som
  hver klone allerede har. Behandle legitimasjonen som lekket og bytt den ut. Å skrive om
  historikken etterpå begrenser spredningen, men kopier som ble laget i mellomtiden, beholder de
  gamle commitene.
- **En tvungen push overskriver en kollegas arbeid.** `git push --force` slår av kontrollen av at
  grenen i fjernrepoet er en forfar til det du pusher, så commits en kollega har pushet i
  mellomtiden, faller ut av grenen. `--force-with-lease` oppdaterer fjernrepoet bare så lenge det
  fortsatt peker dit du sist så det.
- **Klonene blir behandlet som sikkerhetskopien.** En kopi på en bærbar maskin henger etter, holder
  bare de grenene eieren tilfeldigvis har hentet, og ingen har noen gang gjenopprettet fra den med
  vilje. Saker, tilgangsregler og resten av forgens egne data ligger helt utenfor repoet.
- **En stor binærfil gjør hver klone tyngre for godt.** Siden git tar vare på hver versjon av hver
  fil, og hver klone laster ned alle sammen, følger en video som ble committet ved et uhell og
  slettet dagen etter, likevel med til hver maskin som kloner prosjektet senere.
- **Arbeid som bare ligger ett sted, forsvinner med det stedet.** Refloggen som redder en mislykket
  reset, ligger på én maskin og går ut på dato. Commits som aldri ble pushet, finnes ingen andre
  steder, og en gren som får ligge i fred i månedsvis, driver så langt unna at det blir et eget
  prosjekt å flette den inn igjen.

## Les mer

- [Git-dokumentasjonen](https://git-scm.com/doc) — referansemanualen, boken og videoene, fra
  prosjektet selv.
- [Pro Git](https://git-scm.com/book/en/v2) — hele boken på nett, fra den første commiten til
  objektdatabasen under.
- [What is Git?](https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F) — øyeblikksbilder,
  lokale operasjoner, sjekksummer og de tre tilstandene i ett kapittel.
- [A Short History of Git](https://git-scm.com/book/en/v2/Getting-Started-A-Short-History-of-Git) —
  hvorfor kjernemiljøet skrev sitt eget verktøy i 2005, og hva det skulle oppnå.
- [git-reflog](https://git-scm.com/docs/git-reflog) — hvordan du finner ut hvor en gren pekte før
  feilen, og hvor lenge den oversikten varer.
- [git-push](https://git-scm.com/docs/git-push) — valgene for tvungen push, og hva hvert av dem
  beskytter.

<https://engineer.company/nb/glossary/git/>
