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

Gode commits: små, bevisste og godt beskrevne

Modul 1: Grunnmuren · 12 min

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

Etter leksjonen kan du

  • dele blandede endringer i commits med én hensikt hver, også inne i én fil med git add -p anvende
  • skrive en commitmelding med en kort emnelinje i imperativ og en brødtekst som forklarer hvorfor anvende
  • bruke .gitignore for å holde byggfiler, logger og hemmeligheter utenfor historikken, og forklare hvor grensen går anvende

Forstå: Én commit, én hensikt

Tenk deg en commit som heter Fix stuff. Den retter en skrivefeil, legger til en ny uke i planen og tar med en loggfil ved et uhell. Om en måned vet ingen hva den var til. Å angre bare én del blir også tungvint.

Her er det samme arbeidet som to små commits, og loggfilen er ikke med i det hele tatt. Hver commit har én hensikt. Da blir de lettere å lese, lettere å angre og lettere å lete i når en feil dukker opp.

Se på meldingene. Emnelinjen er kort, helst under femti tegn, og skrevet i imperativ, som en ordre: Add exam week, ikke Added stuff. Den fullfører setningen «If applied, this commit will». Begrunnelsen skriver du i en brødtekst etter en tom linje.

Men hva om begge endringene ligger i samme fil? Vi spoler tilbake til før commitene. git add -p viser endringene i blokker, kalt hunks, og spør om hver av dem. Her er bare skrivefeilen staget. Den nye uken venter i arbeidsmappen.

Noen filer skal aldri inn i historikken: byggfiler, logger og hemmeligheter som passord. Filen .gitignore lister mønstre, for eksempel *.log. Usporede filer som passer, viser Git ikke lenger, og git add . hopper over dem. Selve .gitignore committer du som en vanlig fil.

Ignore har to grenser. Den påvirker ikke filer Git allerede sporer. Og den er ingen sikkerhetsmekanisme: har et passord først havnet i en commit som er delt, ligger det i historikken. Da må passordet byttes.

Se demo: Del opp en blandet endring

Vi har jobbet en stund i en kursplan. Statusen viser to ting. plan.txt er endret. debug.log er usporet: en logg programmet skrev, som ikke hører hjemme i historikken.

$ git status --short

Diffen har to blokker som starter med to krøllalfa. Hver blokk er en hunk. Den første retter en skrivefeil i uke to. Den andre legger til uke elleve. To ulike hensikter, altså to commits.

$ git diff

git add -p spør hunk for hunk. Vi svarer y, ja, på skrivefeilen og n, nei, på den nye uken. printf skriver bare svarene for oss, så demoen ikke stopper opp. Nå har plan.txt ulikt innhold i staging-området og i arbeidsmappen.

$ printf 'y\nn\n' | git add -p plan.txt

Før vi committer, sjekker vi utkastet. git diff --staged viser bare rettingen av skrivefeilen. Akkurat det skal med.

$ git diff --staged

Emnelinjen er kort, i imperativ, og sier hva commiten gjør. Den andre -m blir brødteksten, som forklarer hvorfor. Uke elleve er fortsatt bare i arbeidsmappen.

$ git commit -m "Fix typo in week 2" -m "The misspelling made the plan hard to search."

Nå loggfilen. Vi lager en .gitignore med mønsteret *.log. Det betyr alle filer som slutter på .log, i alle mapper.

$ echo "*.log" > .gitignore

Hva viser statusen nå, tror du?

$ git status --short

Oppgaver

  1. Les endringene som ikke er staget.
  2. Stage bare rettingen av skrivefeilen i plan.txt, ikke den nye uken.
  3. Commit rettingen av skrivefeilen med en kort emnelinje og en brødtekst som forklarer hvorfor.
  4. Få Git til å ignorere alle .log-filer.
  5. Sjekk statusen igjen.

Øv: Overfør: rydd i et oppskriftsprosjekt

Et annet prosjekt: en oppskrift, en lokal fil med hemmeligheter, en byggmappe og en loggfil som ble committet ved en feil. Se på git status først.

Oppgaver

  1. .env inneholder hemmeligheter, og build/ lages på nytt av byggverktøyet. Få Git til å slutte å foreslå begge, og commit regelen i en egen commit. Hemmelighetene og byggfilene skal ikke inn i historikken.
  2. recipe.txt har to uavhengige endringer: en retting av stavemåten og et nytt serveringstips. Commit bare rettingen. Gi commiten en emnelinje på høyst 50 tegn og en brødtekst som forklarer hvorfor.
  3. app.log ble committet ved en feil, og Git viser endringer i den hele tiden. Slutt å spore filen og få Git til å ignorere den, men behold den på disken. Lagre dette i en commit.

Sjekk deg selv: Hent det fram igjen

Hvilken emnelinje er best?

  • Added password reset link to login page
  • Add password reset link to login page
  • Add reset link because users could not find it

config.env med et passord ble committet og pushet forrige uke. I dag legger du config.env inn i .gitignore. Hva skjer?

  • Git fjerner filen fra historikken
  • Ingenting for den filen: Git sporer den fortsatt, og passordet ligger i historikken
  • Filen forsvinner fra GitHub ved neste push

I samme fil har du rettet en feil og formatert en funksjon som ikke har noe med feilen å gjøre. Hvordan bør du committe?

  • Én commit, siden det er én fil
  • To commits: stage feilrettingen med git add -p, commit, og commit formateringen etterpå
  • Vent og commit alt samlet på slutten av dagen

Repetisjon fra leksjonen om de tre områdene: du har staget én hunk i plan.txt. Så retter du en ny skrivefeil i samme fil og kjører git commit -m "Fix typo" uten å stage igjen. Hva viser git status --short for plan.txt etterpå?

  • Ingenting, fordi commiten tok med hele filen
  • M i første kolonne: endringen er staget og venter
  • M i andre kolonne: endret i arbeidsmappen, ikke staget

Vanlige misforståelser

  • «En commit er én fil, eller én arbeidsdag.» En commit er én hensikt. Den kan berøre mange filer, eller bare en del av én.
  • «.gitignore skjuler filer som allerede er committet, og beskytter hemmeligheter.» Ignore gjelder bare usporede filer. En hemmelighet som er pushet, må byttes ut.

Les mer

Hva gjør en commit god?

  • Én hensikt. En commit som gjør én ting, er lett å lese i en code review, lett å angre med git revert og lett å finne igjen når du leter etter commiten som innførte en feil.
  • Hel. Den motsatte feilen er å dele for mye. En commit som etterlater prosjektet ødelagt, for eksempel en funksjon uten kallet som trengs, gjør historikken vanskeligere å bruke. Hver commit bør helst bygge og bestå testene.
  • En fast arbeidsrytme: rediger, les git diff, stage det som hører sammen, les git diff --staged, commit, og kjør testene.

git add . er raskt, men upresist: det tar med alt under mappen, også filer du glemte at fantes. Navngi filene, eller bruk git add -p.

Commitmeldingen

Fix typo in week 2
The misspelling made the plan hard to search for
"staging". No other weeks are affected.
  • Emnelinjen er kort, helst høyst 50 tegn, i imperativ og uten punktum. Den fullfører setningen «If applied, this commit will …». Skriv Add exam week, ikke Added stuff.
  • En tom linje skiller emne og brødtekst. Verktøy som git log --oneline viser bare emnelinjen.
  • Brødteksten forklarer hvorfor og eventuelle følger. Hva som ble endret, viser diffen allerede. Bryt linjene rundt 72 tegn.

Med -m to ganger blir første verdi emnelinjen og andre verdi et eget avsnitt:

$ git commit -m "Stop tracking app.log" -m "The log is rewritten on every run and only adds noise to diffs."
$ git log -1
commit b33e60b41b7756c5b4e28b6a7ff2abfc63dbf542
Author: Student <student@example.invalid>
Date:   Tue Oct 13 09:10:51 2026 +0200
    Stop tracking app.log
    The log is rewritten on every run and only adds noise to diffs.

Uten -m åpner git commit editoren som er satt i core.editor. Linjer som starter med #, fjernes. Lagrer du en tom melding, avbrytes commiten. git commit -v viser i tillegg diffen nederst i editoren, så du ser hva du beskriver.

git add -p i detalj

git add -p deler endringene i hunks og spør for hver av dem:

$ git add -p plan.txt
diff --git a/plan.txt b/plan.txt
index f757011..e85757e 100644
--- a/plan.txt
+++ b/plan.txt
@@ -1,6 +1,6 @@
 Course plan
 Week 1: snapshots
-Week 2: stagign
+Week 2: staging
 Week 3: history
 Week 4: branches
 Week 5: merging
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?

Bokstavlisten i hakeparentesen varierer litt mellom Git-versjoner. Disse svarene finnes i alle:

Svar Betyr
y / n Stage denne hunken / hopp over den
a / d Stage resten av hunkene i filen / hopp over resten
s Del hunken i mindre biter, når det finnes uendrede linjer mellom endringene
e Rediger hunken for hånd
q Avslutt. Det du har svart ja på, er fortsatt staget
? Vis hjelp

Etterpå viser git status --short filen som MM: én del er staget, resten venter. Kontroller alltid med git diff --staged før du committer. Har du staget en hunk for mye, tar git restore --staged -p den ut igjen, med de samme spørsmålene.

Hva git commit -a tar med

-a stager endringer og slettinger i filer Git allerede sporer, og committer. Nye filer blir ikke med, og du hopper over sjekken av utkastet:

$ echo tmp > notes.txt
$ git commit -am "Add notes"
On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
    notes.txt
nothing added to commit but untracked files present (use "git add" to track)

.gitignore-mønstre

Mønster Treffer
*.log Alle filer som slutter på .log, i alle mapper
build/ Alle mapper som heter build, med alt innhold
/todo.txt Bare todo.txt i rotmappen
!keep.log Unntak: keep.log skal likevel vises
docs/**/*.pdf PDF-filer på alle nivåer under docs
# tekst En kommentar

Ignorerte filer forsvinner fra git status. --ignored viser dem med !!, og git check-ignore -v forteller hvilken regel som slo til. En regel som starter med !, betyr at filen likevel ikke ignoreres:

$ git status --short --ignored
 M plan.txt
?? .gitignore
?? keep.log
!! build/
!! debug.log
$ git check-ignore -v debug.log build/a.js keep.log
.gitignore:2:*.log  debug.log
.gitignore:3:build/ build/a.js
.gitignore:4:!keep.log  keep.log

Prøver du å stage en ignorert fil, sier Git fra:

$ git add other.log
The following paths are ignored by one of your .gitignore files:
other.log
hint: Use -f if you really want to add them.
  • .gitignore committes og deles med alle. Lokale unntak som bare gjelder deg, skriver du i .git/info/exclude. Filer som editoren eller operativsystemet lager, som .DS_Store eller .idea/, passer best i en global fil satt med core.excludesFile.
  • Git sporer bare filer, ikke tomme mapper. Vil du ha en tom mappe med, legger du en liten fil i den, ofte kalt .gitkeep.

Når filen allerede er sporet

Ignore gjelder bare usporede filer. Er app.log allerede committet, endrer en ny regel ingenting: Git viser fortsatt endringene i den. Slik slutter du å spore den, uten å slette den fra disken:

$ git rm --cached app.log
rm 'app.log'
$ echo "app.log" >> .gitignore
$ git add .gitignore
$ git commit -m "Stop tracking app.log"

git status --short viser D app.log før commiten: filen fjernes fra snapshotet, men blir liggende hos deg. Når andre tar inn commiten med merge eller pull, sletter Git filen fra arbeidsmappen deres.

Hemmeligheter er et eget problem. Gamle commits inneholder fortsatt filen, og alle som har hentet dem, har en kopi. Et passord eller en nøkkel som har vært pushet, må byttes ut. En ny commit som sletter filen, er ikke nok. Commit heller en mal som .env.example uten ekte verdier.

Les videre