Versionshantering

När du arbetar med något som förändras över tid är det användbart att kunna spåra ändringarna. Det finns flera skäl: du får en historik över vad som ändrats, hur du ångrar det, vem som ändrade det, och ibland även varför. Versionshanteringssystem (VCS) ger dig den förmågan. De låter dig checka in ändringar i en uppsättning filer, med ett meddelande som beskriver ändringen, samt granska och ångra tidigare ändringar.

De flesta VCS stöder delning av incheckningshistorik mellan flera användare. Det möjliggör smidigt samarbete. Du kan se ändringarna jag gjort, och jag kan se ändringarna du gjort. Eftersom VCS spårar ändringar kan systemet ofta (men inte alltid) räkna ut hur våra ändringar kan kombineras, så länge de rör relativt separata delar.

Det finns väldigt många VCS-system, och de skiljer sig mycket i vad de stödjer, hur de fungerar, och hur man interagerar med dem. Här fokuserar vi på git, ett av de vanligaste, men jag rekommenderar att du också tittar på Mercurial.

Med det sagt, nu till snabbversionen.

Är git mörk magi?

Inte riktigt. Du behöver förstå datamodellen. Vi hoppar över vissa detaljer, men i grova drag är den centrala “saken” i git en incheckning.

Initialt har ett kodförråd (ungefär mappen som git hanterar) inget innehåll och inga incheckningar. Låt oss sätta upp det:

$ git init hackers
$ cd hackers
$ git status

Utdatan här ger faktiskt en bra utgångspunkt. Låt oss gå igenom den och se till att vi förstår allt.

Först: “On branch master”.

Vi hoppar över “No commits yet” eftersom det är självförklarande.

Sedan: “nothing to commit”.

Medan du testar ovan, försök köra git status för att se vad git tycker att du gör. Det är förvånansvärt hjälpsamt.

En incheckning säger du…

Okej, vi har en incheckning. Vad nu?

Vad betyder ett namn?

Namn är uppenbart viktiga i git. De är nyckeln till att förstå mycket av vad som händer i git. Hittills har vi pratat om incheckningshashar, master, och HEAD. Men det finns mer.

Städa upp historiken

Din incheckningshistorik kommer väldigt ofta att se ut så här:

Det är okej för git, men inte särskilt hjälpsamt för ditt framtida jag eller för andra som vill förstå vad som ändrats. git låter dig städa upp detta:

Arbeta med andra

Ett vanligt användningsfall för versionshantering är att låta flera personer göra ändringar i samma filsamling utan att trampa varandra på tårna. Eller rättare sagt, att säkerställa att om de gör det, så skrivs ändringarna inte bara över tyst.

git är ett distribuerat VCS. Alla har en lokal kopia av hela kodförrådet (eller åtminstone allt andra har valt att publicera). Vissa VCS är centraliserade (t.ex. subversion): en server har alla incheckningar, och klienter har bara filerna de har “checkat ut”. I princip har de bara de aktuella filerna och måste fråga servern för allt annat.

Varje kopia av ett git-kodförråd kan listas som ett fjärrförråd. Du kan kopiera ett befintligt kodförråd med git clone ADDRESS (i stället för git init). Detta skapar ett fjärrförråd som heter origin och pekar på ADDRESS. Du kan hämta namn och incheckningar de pekar på från ett fjärrförråd med git fetch REMOTE. Alla namn på remoten blir tillgängliga som REMOTE/NAME, och du kan använda dem som lokala namn.

Om du har skrivåtkomst till ett fjärrförråd kan du ändra namn på fjärren så att de pekar på incheckningar du skapat via git push. Till exempel, låt oss få master på fjärren origin att peka på samma incheckning som vår lokala master pekar på:

Ofta använder du GitHub, GitLab, BitBucket, eller något annat som fjärrförråd. Det är inget “särskilt” ur gits perspektiv. Det är bara namn och incheckningar. Om någon ändrar master och flyttar github/master till sin incheckning (vi återkommer till det strax), kan du efter git fetch github se deras ändringar med git log github/master.

Samarbete i praktiken

Hittills verkar grenar ganska meningslösa. Du kan skapa dem, jobba i dem, men sedan då? Till slut flyttar du väl ändå master till dem, eller?

Förr eller senare måste du slå samman ändringar i en gren med ändringar i en annan, oavsett om ändringarna gjorts av dig eller någon annan. git gör detta med git merge NAME. merge kommer att:

När din stora funktion är klar kan du slå samman dess gren till master, och git ser till att du inte tappar ändringar från någon gren.

Om du har använt git tidigare känner du kanske igen merge under ett annat namn: pull. När du kör git pull REMOTE BRANCH händer följande:

Det här fungerar oftast bra så länge ändringarna i grenarna är separata. Om de inte är det får du en sammanslagningskonflikt. Det låter läskigt.

Du har just löst din första git-sammanslagningskonflikt. \o/ Nu kan du publicera dina färdiga ändringar med git push.

När världar krockar

När du pushar kontrollerar git att ingen annans arbete går förlorat när du uppdaterar namnet på fjärren du pushar till. Det görs genom att kontrollera att fjärrnamnets nuvarande incheckning är en förfader till incheckningen du pushar. Om så är fallet kan git säkert uppdatera namnet. Det kallas snabb framflyttning (fast-forwarding). Om inte vägrar git uppdatera fjärrnamnet och säger att det har tillkommit ändringar.

Om din push nekas, vad gör du då?

Vidare läsning

XKCD om git

Övningar

  1. I ett kodförråd, prova att ändra en befintlig fil. Vad händer när du kör git stash? Vad ser du med git log --all --oneline? Kör git stash pop för att ångra det du gjorde med git stash. I vilket scenario kan detta vara användbart?

  2. Ett vanligt misstag när man lär sig git är att checka in stora filer som inte bör hanteras av git, eller att råka lägga till känslig information. Prova att lägga till en fil i ett kodförråd, skapa några incheckningar, och ta sedan bort filen ur historiken (du kan titta på det här). Om du faktiskt vill låta git hantera stora filer, titta på Git-LFS.

  3. Git är väldigt bra för att ångra ändringar, men man behöver känna till även ovanliga lägen.
    1. Om en fil råkar ändras i en incheckning kan den återställas med git revert. Men om incheckningen innehåller flera ändringar är revert kanske inte bästa val. Hur kan vi använda git checkout för att återställa en filversion från en specifik incheckning?
    2. Skapa en gren, gör en incheckning i den, och ta sedan bort branchen. Kan du fortfarande återställa incheckningen? Titta på git reflog. (Obs: återställ “hängande” saker snabbt, git städar periodiskt bort incheckningar som inget pekar på.)
    3. Om man är för snabb med git reset --hard i stället för git reset kan ändringar lätt gå förlorade. Eftersom ändringarna var mellanlagrade kan de dock återställas. (Titta på git fsck --lost-found och .git/lost-found.)
  4. I valfritt git-kodförråd, titta i mappen .git/hooks. Där finns skript som slutar på .sample. Om du byter namn på dem och tar bort .sample körs de enligt sitt namn. Till exempel körs pre-commit före en incheckning. Experimentera med dem.

  5. Liksom många kommandoradsverktyg har git en konfigurationsfil (dotfile) som heter ~/.gitconfig. Skapa ett alias i ~/.gitconfig så att git graph ger samma utdata som git log --oneline --decorate --all --graph (det här är ett bra kommando för att snabbt visualisera incheckningsgrafen).

  6. Git låter dig också definiera globala ignore-mönster i ~/.gitignore_global. Det är användbart för att förebygga vanliga misstag, som att lägga till RSA-nycklar. Skapa en ~/.gitignore_global-fil, lägg till mönstret *rsa, och testa att det fungerar i ett kodförråd.

  7. När du blir mer van vid git kommer du märka återkommande uppgifter, som att redigera .gitignore. git extras erbjuder många småverktyg som integrerar med git. Till exempel lägger git ignore PATTERN till mönstret i kodförrådets .gitignore, och git ignore-io LANGUAGE hämtar vanliga ignore-mönster för språket från gitignore.io. Installera git extras och testa verktyg som git alias eller git ignore.

  8. Git-GUI-program kan ibland vara mycket användbara. Prova att köra gitk i ett kodförråd och utforska gränssnittets olika delar. Kör sedan gitk --all. Vilka skillnader ser du?

  9. När man väl vant sig vid kommandoradsprogram kan GUI-verktyg kännas tunga. En bra kompromiss är ncurses-baserade verktyg, som kan navigeras från kommandoraden men fortfarande erbjuder ett interaktivt gränssnitt. Git har tig. Prova att installera det och köra det i ett kodförråd. Du hittar användningsexempel här.

Edit this page.

Licensed under CC BY-NC-SA.