På denne siden

Enhver innføring i terminalen forutsetter ett verktøy før alle andre: git. Installeringsguidene begynner med «clone the repository», og før eller siden står det en terminal der og venter på at du skal kunne git. Denne guiden holder seg bevisst frakoblet: det felles lagrepunktet lenger ut er en mappe på din egen disk, ingen hostingtjeneste er involvert. Alt nedenfor er kjørt på git 2.53.0 (Ubuntu 26.04) og 2.56.0 (Fedora 44, Arch), identisk på begge versjoner.

Hva git faktisk gjør

git er en protokollfører. Peker du den på en mappe, kan den ta et snapshot av hele mappen, nøyaktig slik den ligger, når som helst du ber om det. Hvert snapshot er en commit med et kort navn som bc11b6c, og samlet lar commitene deg gå tilbake til enhver tidligere tilstand: lagrepunkter, i spilleforstand. Et repository er bare en mappe med en .git-katalog inni seg, og hver commit lagrer hele prosjektet, så du kan rekonstruere tirsdag morgen og ikke bare filen du angrer på at du rørte.

Installer og presenter deg

Sjekk med git --version om det er der. På Ubuntu betyr dette noe: serverbildet avhenger av git, så en server har det alltid, men en fersk skrivebords- eller minimalinstallasjon mangler det. Fedoras workstation-sett merker det som en standardpakke, og Archs lille base-sett tar det ikke med. Mangler den:

$ sudo apt install git        # Ubuntu, Debian
$ sudo dnf install git        # Fedora
$ sudo pacman -S git          # Arch

Før første commit vil git vite hvem du er. Den stempler et navn og en adresse inn i hver commit, slik at en historie fortsatt betyr noe når flere personer har skrevet deler av den:

$ git config --global user.email "[email protected]"
$ git config --global user.name "Vera Flyer"

Adressen blir ikke sjekket mot noe, og git sender aldri post til noen. Den hogger bare det du taster inn i hver commit. Begge innstillingene lander i ~/.gitconfig, og --global gjør at de gjelder for hvert repository på denne maskinen.

Kjører du en commit uten identitet på fil, stopper git deg. Verdt å se én gang:

Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "[email protected]"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'you@mycomputer.(none)')

Den siste linjen innrømmer at git prøvde å gjette en adresse ut fra vertsnavnet og ga opp.

Ditt første repository

Enhver mappe kan bli et repository. Lag én og slå på git:

$ mkdir projects
$ cd projects
$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: will change to "main" in Git 3.0. To configure the initial branch name
hint: to use in all of your new repositories, which will suppress this warning,
hint: call:
hint:
hint: 	git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: 	git branch -m <name>
hint:
hint: Disable this message with "git config set advice.defaultBranchName false"
Initialized empty Git repository in /home/you/projects/.git/

Hintene kaller branchen master og sier at denne standarden endres til «main» i Git 3.0. Det er gits ordlyd, ikke et løfte om at navnet varer, så les main der denne guiden skriver master når den dagen kommer. Linjen som betyr noe, kommer sist: repositoryet finnes, i .git-katalogen git nettopp opprettet. Spør den hvordan det går:

$ git status
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)

Hvert ord der er vokabular: tre tilstander, tre ord. En fil er untracked når git ser den, men du ikke har bedt git om å føre protokoll over den, staged når git add har markert tilstanden dens for neste commit, og committed når det finnes et snapshot som inneholder den. git status er kartet over hvor hver fil står.

Den daglige løkken

Løkken du kommer til å taste tusen ganger, er add, så commit. Start med en navngitt fil, og la deretter prikken overta:

$ echo "backup plan: rsync to the Pi" > notes.txt
$ git add notes.txt
$ git commit -m "First commit"
[master (root-commit) bc11b6c] First commit
 1 file changed, 1 insertion(+)
 create mode 100644 notes.txt
$ mkdir src
$ echo "# Scripts" > README.md
$ git add .
$ git commit -m "Add src and readme"
$ git log --oneline
09aecf2 Add src and readme
bc11b6c First commit
$ git log
commit 09aecf24b6f75067a6453a79752811861fb847d3
Author: Vera Flyer <[email protected]>
Date:   Mon Oct 12 07:15:35 2026 +0000

    Add src and readme

git add stager og flytter en fil til kartets mellomtilstand. Prikken stager alt som ligger løst, og det er slik søppel sniker seg inn i historien (avsnittet om ignorering har filteret). Tomme kataloger er usynlige for git, så src kommer inn i historien bare gjennom filene sine. git commit -m fotograferer alt som er staget, og den første commiten er en root-commit med utdata som navngir branchen og den nye korte hashen. --oneline klemmer hver commit inn til hash og melding, nyeste først, og fullformen legger til forfatteren og datoen konfigen din stemplet inn. Hashene her tilhører testkjøringen. Dine er annerledes hver gang, og det er normalt. Én runde til, nå med redigering av en eksisterende fil:

$ nano notes.txt
$ git add notes.txt
$ git commit -m "Edit notes"
[master dc6d8fc] Edit notes
 1 file changed, 1 insertion(+), 1 deletion(-)

Sammendraget teller nå slettinger også. Det er hele løkken: git status for å se, git add for å stage, git commit -m for å føre på protokoll, git log for å lese tilbake.

Se på endringer

Tre vinduer mot endring, ved tre anledninger. git diff skriver ut redigeringene du har gjort, men ennå ikke staget, arbeidet en commit akkurat nå ville utelate. git diff --staged skriver ut den andre halvdelen: alt en commit akkurat nå ville tatt med. Før du committer, forteller den første deg hva du lar ligge igjen, og den andre hva du skriver ned. git show HEAD skriver ut selve nyeste commit, melding og endringer sammen, der HEAD er gits kortform for nettopp den nyeste commiten.

Angre ting

Kommandoen du vil ønske deg mest, er også den du skal håndtere med forsiktighet. git restore FILE setter en fil tilbake til sin sist registrerte tilstand og kaster bort redigeringene du ikke har committet. Dette sletter arbeidet ditt, og det finnes ingen papirkurv å fiske det ut av. På en fil git aldri har sett, nekter den å gjette:

$ echo "scrapped plan" > notes.txt
$ git restore notes.txt
$ git restore extra.txt
error: pathspec 'extra.txt' did not match any file(s) known to git

Skaden er borte, og notes.txt leser seg slik den gjorde ved siste commit. Feilmeldingen er nøyaktig: restore virker på filer git kjenner, og extra.txt kom aldri inn i en commit eller en add. Ett punkt med liten skrift: som standard henter restore kopien sin fra staging-området, ikke fra siste commit. Er ingenting staget, er de to like, og det er derfor den enkle beskrivelsen holder. En halvstaget fil gjør dem ulike, og den blandingen er der manualen begynner.

Den milde undoen ruller tilbake en staging-beslutning. Du kjørte git add TODO.md i fart og bestemte deg for at filen ikke er klar. git restore --staged TODO.md angrer nøyaktig det. Bare stagingen forsvinner. Redigeringene blir liggende på disken, og neste commit slutter bare å ta dem med. Der vanlig restore kaster arbeid bort, endrer --staged meningen din.

Den tredje undoen reparerer selve commiten. Commit en liste med ett element, og kom så på det andre elementet:

$ echo "milk" > list.txt
$ git add list.txt
$ git commit -m "Add list with one item"
$ echo "eggs" >> list.txt
$ git add list.txt
$ git commit --amend -m "Add list with two items"
[master 70a66be] Add list with two items
 Date: Mon Oct 12 07:17:57 2026 +0000
 1 file changed, 2 insertions(+)
 create mode 100644 list.txt

--amend erstatter nyeste commit med en ny, bygget fra den gamle commiten pluss det som er staget nå. Hashen er ny, 70a66be, for dette er en annen commit som bærer den korrigerte meldingen. Den skriver til og med ut en Date:-linje, noe en vanlig commit aldri viser. Amend omskriver historien, så å gjøre det mot noe som allerede er pushet, omskriver historie som andre kopier kan holde. Amend er for commits som fortsatt er helt dine.

Branches uten frykt

En branch er et navn på en arbeidslinje, og fire kommandoer dekker det. git branch feature oppretter én og sier ingenting (i git betyr stillhet at det gikk bra), mens git branch alene lister dem alle og merker der du står med en stjerne:

$ git branch feature
$ git branch
  feature
* master

Ingenting flyttet seg: å opprette en branch skrev bare navnet ned. Å bytte er et eget steg, og -c oppretter og bytter i én bevegelse:

$ git switch feature
Switched to branch 'feature'
$ git switch -c hotfix
Switched to a new branch 'hotfix'

Meldingene skiller seg med to ord. Eldre tutorialer skriver git checkout for dette. git switch er den moderne erstatteren, og begge skriver ut Switched to a new branch 'NAME'. Nå kommer gevinsten. Commit på en branch, vend tilbake til master, merge:

$ echo "new thing" > feature.txt
$ git add feature.txt
$ git commit -m "Add feature"
$ git switch master
Switched to branch 'master'
$ git merge feature
Updating dc6d8fc..f4354cb
Fast-forward
 feature.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 feature.txt

Fast-forward er det glade tilfellet: master lagde ingen egne commits mens feature var ute, så mergen skyver master opp til features nyeste commit. Updating-linjen navngir de to posisjonene som hasher.

Én vegg er ekte: endret begge branches de samme linjene i samme fil, stopper git mergen og ber deg bestemme hva resultatet skal si. Å redde ut den knuten, en mergekonflikt, er en ferdighet for seg og utenfor denne guiden.

Ignorere filer

Enhver arbeidsmappe samler filer som er dine, men ikke prosjektets: logger fra testkjøringer, byggutdata, editorrester. En .gitignore i repositoryroten lister opp det git skal se bort fra:

# test runs leave these behind
*.log
build/

Linjer som begynner med # er kommentarer, *.log matcher alle navn som slutter på .log, og build/ med skråstreken bakerst matcher byggkatalogen.

Nå til fellen: .gitignore påvirker bare filer git ikke allerede sporer. Commit debug.log, og skriv *.log etterpå, og git fortsetter å spore den som om ingenting hendte. Redigeringer dukker fortsatt opp som endringer og seiler inn i hver commit, mens en helt ny logg ved siden av ville blitt ignorert. Listen styrer hva git plukker opp fremover. Den gjør ingenting usett.

Å få git til å glemme en fil den sporer, krever git rm --cached FILE, som slutter å spore den og lar filen ligge på disken. For i dag er det nok å vite at fellen finnes.

Remotes på egen disk

Ekte team lar det delte repositoryet sitt ligge hos en hostingtjeneste, og de samme kommandoene kjører mot en URL i stedet for en bane når du blir med i en. Å bli på egen disk er poenget: det lærer deg grepene, og et lagrepunkt på en ekstern stasjon er en ekte sikkerhetskopi.

Pusher du til en vanlig mappe, nekter git:

remote: error: refusing to update checked out branch: refs/heads/master
To /tmp/vfygit/demo
 ! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to '/tmp/vfygit/demo'

(remote:-linjene bærer etterfølgende mellomrom i ekte utdata, fjernet her, og gits nektelsesmelding fortsetter utover dette utdraget.) Grunnen står i første linje: branchen i målet er checked out, så det kan stå noen i den mappen og redigere akkurat de filene et push ville erstattet. git beskytter den arbeidskopien.

Fiksen er et bart repository: ingen arbeidstre, ingen som redigerer inni det, ingenting å beskytte, pushes er velkomne. Etter konvensjon slutter navnet på .git. Fem linjer utgjør hele den frakoblede arbeidsflyten:

git init --bare /path/to/savepoints.git   # the shared save point (bare = no working tree, accepts pushes)
git remote add origin /path/to/savepoints.git
git push -u origin master
git clone /path/to/savepoints.git
git pull

origin er et kallenavn for den banen, ikke mer. -u på første push ber git huske koblingen, så hver push etter den kan være en vanlig git push. En første push fra testkjøringen, med tomt lagrepunkt:

To /tmp/vfygit/savepoints.git
 * [new branch]      master -> master
branch 'master' set up to track 'origin/master'.

Sporingslinjen er -u som gjør jobben sin: origin/master er posten din over hvor master befinner seg på lagrepunktet. Pusher du igjen uten noe nytt, er svaret kort: Everything up-to-date.

En annen maskin, eller en annen mappe på den samme, starter fra lagrepunktet med clone, og git har allerede skrevet ned hvor kopien kom fra:

$ git clone /tmp/vfygit/savepoints.git laptop
Cloning into 'laptop'...
done.
$ git remote -v
origin	/tmp/vfygit/savepoints.git (fetch)
origin	/tmp/vfygit/savepoints.git (push)

Commiten som kommer inn, ble redigert, addet, committet og pushet fra den første mappen, så denne pullen har noe å hente. Pullens From-linje skriver ut banen uten .git, mens git remote -v viser den med:

$ git pull
From /tmp/vfygit/savepoints
   347bcf7..9723a2e  master     -> origin/master
Updating 347bcf7..9723a2e
Fast-forward
 notes.txt | 2 ++
 1 file changed, 2 insertions(+)

Pull hentet den nyeste tilstanden og foldet den inn. Fast-forward igjen, for denne klonen hadde ikke laget noen egne commits. Er ingenting i vente: Already up to date.

To fotnoter. De samme kommandoene virker mot you@server:/path/repo.git over SSH. SSH-guiden dekker nøkkelautentisering. Og receive.denyCurrentBranch=updateInstead lar et ikke-bart repository ta imot pushes og oppdatere arbeidstreet sitt.

Avslutningsprosjekt — en versjonert skriptmappe

Kjør hele buen i én omgang. Materialet er skriptene fra bash-skriptguiden: den voksne backup.sh, pluss check.sh-utdraget fra guidens testseksjon, for planlagte skript er det første som er verdt å versjonere. Automatiseringskapittelet er der de møter cron.

Lagre den endelige backup.sh fra den guiden i en ny ~/scripts-mappe først, og presenter deg som i installasjonsavsnittet hvis denne maskinen ikke har møtt deg før. Så:

$ cd ~/scripts
$ git init
$ git add backup.sh
$ git commit -m "Track the backup script"
[master (root-commit) 730adaa] Track the backup script
 1 file changed, 19 insertions(+)
 create mode 100644 backup.sh

Nytt arbeid legges på en branch først, alltid. Opprett én, lagre guidens check.sh i mappen, stage, commit, og fold deretter branchen tilbake inn i master:

$ git switch -c add-check
Switched to a new branch 'add-check'
$ git add check.sh
$ git commit -m "Add check script"
$ git switch master
Switched to branch 'master'
$ git merge add-check
Updating 730adaa..127d7c0
Fast-forward
 check.sh | 5 +++++
 1 file changed, 5 insertions(+)
 create mode 100644 check.sh

Med skriptene inne, vokt deg mot søppel før det finnes noe: en .gitignore med mønstrene fra avsnittet om ignorering, laget med nano. Commit den så:

$ git add .gitignore
$ git commit -m "Ignore test logs"
[master dcf3ec5] Ignore test logs
 1 file changed, 3 insertions(+)
 create mode 100644 .gitignore

Siste steg, selve lagrepunktet. Et bart repository på samme disk er en fotokopi i det samme brennende bygget, men riktig form for en ekstern stasjon eller en annen maskin:

$ git init --bare /home/you/savepoints.git
$ git remote add origin /home/you/savepoints.git
$ git push -u origin master
To /home/you/savepoints.git
 * [new branch]      master -> master
branch 'master' set up to track 'origin/master'.
$ git push
Everything up-to-date

Det andre pushet beviser at lagrepunktet stemmer med mappen. Fra hvor som helst annet henter git clone /home/you/savepoints.git work ned alle tre commitene, og git pull holder dem oppdaterte.

Hvor du står nå

Du kan versjonere en mappe fra ende til annen: init, add, commit, branch, merge, restore, ignorere, og pushe til et bart repository på egen disk. Fire vaner bærer det meste av vekten. Kjør git status når du er usikker, og git diff --staged før du committer. Rekk etter restore --staged før vanlig restore når du hadde tenkt å beholde arbeidet. Og amend aldri en commit som allerede er pushet.

Bevisst hoppet over: mergekonflikter, git stash, hostingplattformer og alt som følger med dem, og gits dypere historiekirurgi. Alt venter til et ekte prosjekt krever det.

To referanser, begge offisielle og stabile: