GIT
Förtydliga gits strategi att hantera "content" istället för "filer". Lägg in exempel med fler än en fil.
Vad är GIT?
[redigera]GIT är ett distribuerat versionshanteringssystem skapat av Linus Torvalds för användning i Linux-projektet. TODO.....
Grundläggande revisionshantering
[redigera]Den här guiden går igenom hur man skapar ett GIT-repository och börjar arbeta med det. För att ha något konkret att versionshantera skriver vi en simpel applikation i programmeringsspråket Python. Du behöver dock inte kunna programmera vare sig Python eller något annat språk för att följa guiden.
Installera GIT
[redigera]Om du kör någon variant av GNU/Linux finns GIT med stor sannolikhet färdigpaketerat till din distribution. Om distributionen är baserad på Debian så installerar du GIT genom att skriva in följande i en terminal
sudo apt-get install git-core
Kör du Windows så finns GIT paketerat till Cygwin.
Ställ in dina användaruppgifter
[redigera]Mata in följande i en terminal där du ersätter namnet och e-mailen med dina egna uppgifter.
git config --global user.name "Inge Glid" git config --global user.email ingeglid@nosuchmail.com
Nu kommer dina historikposter visa ditt namn och din e-mail, det underlättar för andra utvecklare som kan tänkas vilja kontakta dig.
Skapa en ny tom GIT-repository
[redigera]Öppna en terminal (starta Cygwin ifall du kör Window) och skriv in de kommandon som inte börjar med "#". "#"-raderna är kommentarer och finns bara till för att förklara vad varje enskilt kommando gör.
# skapa en tom mapp mkdir hellopy # gå till den nya mappen cd hellopy # initiera ett tomt GIT-repo git init
GIT svarar
Initialized empty Git repository in .git/
Lägg till en ny fil "hello.py" och skapa en historikpost
[redigera]Låt oss nu skapa ett minimalt Python-program som skriver ut texten "Hello" på skärmen. Nedan används texteditorn "GEdit" som finns installerad på många GNU/Linux-system, men kör du tex. Windows så fungerar "notepad" lika bra
# Öppna en texteditor gedit hello.py
Skriv in följande text i editorn
#!/usr/bin/python print "Hello"
Spara filen och stäng editorn. Återgå till terminalfönstret. Nu ska vi se vad som hänt i vår mappstruktur
# Kolla nuvarande status git status
GIT svarar
# On branch master # # Initial commit # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # hello.py nothing added to commit but untracked files present (use "git add" to track)
GIT har här upptäckt en fil som inte är versionshanterad. Om vi vill att GIT ska börja versionshantera filen så får vi lägga till den med kommandot
# lägg till hello.py git add hello.py
Nu vill vi spara det nuvarande läget för hello.py i GIT:s historik. Då gör vi en "commit" enligt
# spara läget för de tillagda filerna som en historikpost ("commit") git commit -m "Vår första commit"
GIT svarar
Created initial commit db16eeb: Vår första commit 1 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 hello.py
Kör vi nu återigen "git status" så svarar GIT
# On branch master nothing to commit (working directory clean)
Vilket glädjande betyder att vi inte glömt att versionhantera någon fil i trädet och att alla ändringar finns sparade i en historikpost ("commit").
I texten som följer arbetar vi av pedagogiska skäl bara med en fil "hello.py", men det går givetvis att lägga till hur många filer som helst och arbeta med dem på samma sätt.
Gör en ändring i "hello.py" och spara den som en ny historikpost
[redigera]Låt oss utvidga vårt program till att fråga efter namnet på användaren på användaren och därefter hälsa på honom/henne.
# Öppna hello.py gedit hello.py
Utvidga programmet till följande
#!/usr/bin/python name = raw_input("What is your name? ") print "Hello " + name
Spara filen och stäng editorn. Nu ska vi se vad som hänt i repon genom att köra
# Kolla statusen git status
GIT svarar
# On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # # modified: hello.py # no changes added to commit (use "git add" and/or "git commit -a")
Det visar att GIT upptäckt en ny ändring i "hello.py". Vill vi se exakt vad som ändrats i "hello.py" kan vi köra följande
# se vad som ändrats i "hello.py" sedan senaste commiten git diff
GIT svarar
--- a/hello.py +++ b/hello.py @@ -1,2 +1,5 @@ #!/usr/bin/python -print "Hello" + +name = raw_input("What is your name? ") +print "Hello " + name +
Ändringen visas som en "diff". Dessa kan till en början vara lite krytiska att läsa men man lär sig ganska snart tolka dem. Raderna med "+" berättar vad som lagts till och rader som börjar med "-" visar vad som raderats. Här har den ursprungliga print-raden tagits bort och ersatts med fyra andra rader
Låt oss göra en "commit" enligt
# spara nuvarande läget som en historikpost git commit -m "Nu frågar programmet efter användarens namn och skrivet ut en hälsning"
GIT svarar
# On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # # modified: hello.py # no changes added to commit (use "git add" and/or "git commit -a")
Hm, vi har visst glömt en sak. Vi måste lägga till hello.py innan vi kan göra en commit. Vill vi göra tilläggningen och commiten i ett steg så kan vi använda "-a" flaggan till "commit".
# lägg till alla sedan tidigare versionhanterade filer och gör en commit git commit -a -m "Nu frågar programmet efter användarens namn och skrivet ut en hälsning"
GIT svarar
Created commit 2adc044: Nu frågar programmet efter användarens namn och skrivet ut en hälsning 1 files changed, 4 insertions(+), 1 deletions(-)
Lista historiken
[redigera]Vill man se vilka commits som gjorts kan man lista historiken med följande kommando
git log
GIT svarar
commit 2adc0443929fe09111a37ab66573db20415985f0 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:59:43 2008 +0200 Nu frågar programmet efter användarens namn och skrivet ut en hälsning commit db16eeb9c48d0b67e496e59fbaca154d0ffc02fb Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:32:10 2008 +0200 Vår första commit
Den långa hex-strängen efter "commit" är en kontrollsumma beräknad med den krypografiska hashtekniken SHA-1 och beräkningen sker baserat på alla tidigare commits. Många andra versionhanteringssystem nöjer sig med ett simpelt löpnummer, så varför krånglar GIT till det? SHA-1 identifieringen gör det möjligt att upptäcka ifall historiken blivit korrupt, kanske pga. en trasig hårddisk, ett trasigt RAM-minne eller att någon illvillig användare försökt förändra innehållet. Det gör GIT till ett robust och säkert sätt att versionhantera sina projekt med.
Ångra en ocommitad ändring
[redigera]Låt oss göra en ändring i programmet. Öppna hello.py och ändra texten till
#!/usr/bin/python name = raw_input("What is your name? ") print "Hello " + name print "It was nice to see you"
Vi sparar filen och märker sedan att vi vill ångra denna ändring. I det här trivala fallet är det trivalt att bara öppna filen och återställa innehållet (då kommer förresten "git log" rapportera att ingenting förändrats) men nu simulerar vi att vi gjort många felaktiga ändringar i en större kodbas.
Vi kör då kommandot
git reset --hard
GIT svarar
HEAD is now at 2adc044 Nu frågar programmet efter användarens namn och skrivet ut en hälsning
GIT har nu tagit bort alla ändringar vi inte commitat. Med andra ord är vi tillbaka i det läget vi hade vid den förra commiten (dock bara för de filer som vi versionhanterar).
För att kontrollera att det fungerar öppnar vi hello.py. Innehållet är som väntat
#!/usr/bin/python name = raw_input("What is your name? ") print "Hello " + name
Ångra en commitad ändring (eller flera)
[redigera]Låt oss göra en ny "felaktig" ändring som vi dessutom är dumma nog att commita
Ändra hello.py till
#!/usr/bin/python print "Hello " + name
Spara och commita enligt
git commit -a -m "Dum dum, tog bort inmatningsraden"
En logvisning enligt
git log
ger
commit 5c93f3b3b63eb50bf94dc90bcd9b4cec1e1831d2 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 00:46:45 2008 +0200 Dum dum, tog bort inmatningsraden commit 2adc0443929fe09111a37ab66573db20415985f0 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:59:43 2008 +0200 Nu frågar programmet efter användarens namn och skrivet ut en hälsning commit db16eeb9c48d0b67e496e59fbaca154d0ffc02fb Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:32:10 2008 +0200 Vår första commit
Nu vill vi gå tillbaka till läget vid den föregående commiten, då kan vi köra
git revert --no-edit -r HEAD~0
Siffran (i det här fallet "0") anger vilken commit relativt den senaste som vi vill upphäva effekten av. Ett högre tal hade backat längre bak i historiken. I just det här fallet är "-r HEAD~0" överflödigt eftersom "0" är förvalt men jag visar hur man gjort i det generella fallet. Om revisionen ligger långt bak och det är besvärligt att ta reda på hur många steg vi vill upphäva så kan man ange (minst) de fyra första siffrorna i SHA-1-summan istället. I det här fallet hade med andra ord
git revert --no-edit
eller
git revert --no-edit -r 5c93
fungerat lika bra
Som svar på något av kommandoalternativen ovan ger GIT
Finished one revert. Created commit feed231: Revert "Dum dum, tog bort inmatningsraden" 1 files changed, 1 insertions(+), 0 deletions(-)
Visar vi historiken ger GIT
Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 00:55:14 2008 +0200 Revert "Dum dum, tog bort inmatningsraden" This reverts commit 5c93f3b3b63eb50bf94dc90bcd9b4cec1e1831d2. commit 5c93f3b3b63eb50bf94dc90bcd9b4cec1e1831d2 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 00:46:45 2008 +0200 Dum dum, tog bort inmatningsraden commit 2adc0443929fe09111a37ab66573db20415985f0 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:59:43 2008 +0200 Nu frågar programmet efter användarens namn och skrivet ut en hälsning commit db16eeb9c48d0b67e496e59fbaca154d0ffc02fb Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:32:10 2008 +0200 Vår första commit
Loggen är tydlig men kanske inte så snygg. Vi vill kanske inte visa vårt misstag utan helt enkelt ta bort historiken efter revision "2adc". Då kan vi återigen bruka "git reset --hard" enligt
git reset --hard 2adc
GIT ger
HEAD is now at 2adc044 Nu frågar programmet efter användarens namn och skrivet ut en hälsning
Var dock riktigt försiktig med detta kommando! Det raderar all historik efter den angivna revisionen och det som tas bort går INTE att återställa.
Historiken visar nu
commit 2adc0443929fe09111a37ab66573db20415985f0 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:59:43 2008 +0200 Nu frågar programmet efter användarens namn och skrivet ut en hälsning commit db16eeb9c48d0b67e496e59fbaca154d0ffc02fb Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:32:10 2008 +0200 Vår första commit
Jämför ändringar gjorda mellan commits
[redigera]Om vi bara kör
git diff
visas vilka ändringar som ännu inte commitats
Vill vi se skillnaden mellan den nuvarande och en föregående revision kör vi tex.
git diff -r db16
eller enklast
git diff -r HEAD~1
vilket ger
diff --git a/hello.py b/hello.py index ba529fa..d7632c8 100644 --- a/hello.py +++ b/hello.py @@ -1,2 +1,5 @@ #!/usr/bin/python -print "Hello" + +name = raw_input("What is your name? ") +print "Hello " + name +
I det mer generella fallet vill vi ange de två revisioner som vi vill jämföra. I det här fallet har vi bara två stycken i loggen så
git diff -r 2adc -r db16
ger samma utdata som ovan. Vill man kan man vända på argumenten och få ett inverterat resultat enligt
diff --git a/hello.py b/hello.py index d7632c8..ba529fa 100644 --- a/hello.py +++ b/hello.py @@ -1,5 +1,2 @@ #!/usr/bin/python - -name = raw_input("What is your name? ") -print "Hello " + name - +print "Hello"
Arbeta med branches
[redigera]GIT gör det väldigt enkelt att skapa och hantera olika branches. En branch är ett parallellt utvecklingsspår och varje branch har sin egen revisionshistoria. Det finns många sätt att använda branches men det vanligaste är att man skapar en branch när man vill utveckla någon experimentell funktion eller göra en ändring som gör projektet "instabilt" under en viss tid. Då vill man fortfarande att andra utvecklare ska kunna hämta ens stabila version och då är det lämpligt att man lägger de två spåren i olika brancher
När man kör "git init" skapar GIT ett repository med en branch "master". Det är den branchen som är tänkt att vara det stabila och publika spåret, så helst ska man inte utveckla på "master" utan jobba på en annan branch och efter hand som funktioner mognar "merga" (smälta samman) de delarna in i "master". merging och branching kan göras mellan vilka brancher man vill, hur ofta eller hur sällan man så vill.
GIT kan hålla flera brancher i samman träd, inte bara i olika mappar såsom andra versionshanteringssystem. Detta spar både uttrymme (eftersom omodifierande delar i olika brancher med samma ursprung delar data) och gör merging och branching väldigt effektivt.
Skapa en ny experimentell branch
[redigera]Anta att vi vill utvidga programmet till att säga hej till ett flertal personer i följd. Då kan vi börja skriva ändringen enligt
#!/usr/bin/python name = "start" while name!="": name = raw_input("What is your name? ") print "Hello " + name
git status
ger
# On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # # modified: hello.py #
och visar att hello.py modifierats
Vi vill inte lägga in ändringen i vår stabila branch "master" utan vi skapar en ny branch "expmultiname" baserat på den nuvarande enligt
git branch expmultiname
Vi byter till den nya branchen med
git checkout expmultiname
GIT svarar
M hello.py Switched to branch "expmultiname"
Båda operationerna göras med snabbkommandot
git checkout -b expmultiname
Den första raden "M hello.py" berättar att hello.py är "dirty" (smutsig), dvs den har ändringar som ännu inte commitats. Observera något väldigt viktigt - ocommitade ändringar reser mellan brancher när man byter mellan dem. I det här fallet är det inga problem då vi påbörjade ändringen innan vi bytte. Vi ville att det vi inte commitat skulle appliceras på den nya branchen, för det är just det som händer. Vill man inte att det ska inträffa kan det lösas genom att man commitar innan man byter branch eller så kan man använda "git stash" som vi återkommer till.
För att lista vilka brancher som finns kör vi
git branch
GIT svarar
* expmultiname master
Låt oss commita ändringen enligt
git commit -a -m "Hälsar och frågar nu i en loop"
GIT svarar
Created commit f6c4c95: Hälsar och frågar nu i en loop 1 files changed, 4 insertions(+), 2 deletions(-) mode change 100644 => 100755 hello.py
Kör vi nu
git status
vilket visar
# On branch expmultiname nothing to commit (working directory clean)
ser vi att vi trädet är "rent", dvs inget ocommitat finns i trädet
Kör vi programmet märker vi att det fungerar fram till att vi ger en tomrad som input. Då avslutar programmet (vilket vi vill), men det lämnar en utskrift "Hello " på en ny rad och det vill vi undvika. Vi fixar buggen genom att skriva om programmet enligt
#!/usr/bin/python while 1: name = raw_input("What is your name? ") if name == "": break print "Hello " + name
Vi kan köra "git status" och/eller "git diff" för att se vad som hänt. Det är en god vana att alltid göra det innan man gör en commit, annars kan man råka commita saker man inte riktigt räknat med. Nåväl, i det här fallet vet vi vad vi gjort så vi kör en commit
git commit -a -m "Fixade bug som skrev ut Hello när programmet avslutades"
En logvisning ger som förväntat
commit 043e861919d386499a7c0df8a847352f8c8b36b5 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 03:19:25 2008 +0200 Fixade bug som skrev ut Hello när programmet avslutades commit f6c4c95a4a66c600cfdea15c0696199a9482d99e Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 03:06:05 2008 +0200 Hälsar och frågar nu i en loop commit 2adc0443929fe09111a37ab66573db20415985f0 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:59:43 2008 +0200 Nu frågar programmet efter användarens namn och skrivet ut en hälsning commit db16eeb9c48d0b67e496e59fbaca154d0ffc02fb Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:32:10 2008 +0200 Vår första commit
Applicera ändringar i den experimentella branchen på den ursprungliga branchen
[redigera]Låt oss byta tillbaka till vår "master"-branch. Innan vi byter kör vi
git status
vilket ger
# On branch expmultiname nothing to commit (working directory clean)
dvs vi kan byta branch utan att riskera att någon ocommitad ändring "liftar med" i branchbytet.
Bytet görs med
git checkout master
Tittar vi på loggen
commit 2adc0443929fe09111a37ab66573db20415985f0 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:59:43 2008 +0200
Nu frågar programmet efter användarens namn och skrivet ut en hälsning
commit db16eeb9c48d0b67e496e59fbaca154d0ffc02fb Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:32:10 2008 +0200
Vår första commit
ser vi att vi ännu inte påverkat master-branchen med vår loop-konstruktion.
Nu ska vi göra någonting kul, merga in ändringarna ifrån vår experimentella branch till master-branchen. Vi kör
git pull . expmultiname
Punkten talar om att vi ska merga med en branch ifrån samma filträd
GIT svarar
Updating 2adc044..043e861 Fast forward hello.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) mode change 100644 => 100755 hello.py
Merging verkar ha gått bra, så låt oss kika på loggen
commit 043e861919d386499a7c0df8a847352f8c8b36b5 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 03:19:25 2008 +0200 Fixade bug som skrev ut Hello när programmet avslutades commit f6c4c95a4a66c600cfdea15c0696199a9482d99e Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 03:06:05 2008 +0200 Hälsar och frågar nu i en loop commit 2adc0443929fe09111a37ab66573db20415985f0 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:59:43 2008 +0200 Nu frågar programmet efter användarens namn och skrivet ut en hälsning commit db16eeb9c48d0b67e496e59fbaca154d0ffc02fb Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:32:10 2008 +0200 Vår första commit
och därefter på koden
cat hello.py
vilket skriver ut hello.py på skärmen
#!/usr/bin/python while 1: name = raw_input("What is your name? ") if name == "": break print "Hello " + name
Perfekt! Låt oss nu bara köra en statuskontroll för att se att allt är okej
git status
vi får
# On branch master nothing to commit (working directory clean)
och ser att vi har ett rent träd
Ta bort den experimentella branchen
[redigera]När ändringarna är mergade in i master finns det ingen direkt anledning att behålla branchen expmultiname. Vi raderar den enkelt genom
git branch -D expmultiname
GIT svarar
Deleted branch expmultiname.
Mer avancerat arbete med branches
[redigera]Göm undan ocommitade ändringar (stashing)
[redigera]Säg att du skrivit lite kod som du ännu inte commitat. Du känner dock att du skulle vilja göra en liten ändring/bugfix på ett annat ställe i koden och commita den ändringen innan din stora ändring. Är det i olika filer så kan du enkelt commita olika filer i olika omgångar, men är det samma fil den lilla och stora ändringen görs i så fungerar inte den metoden. När du kodat en bit på den stora ändringen och känner för att göra den lilla så kör
git stash
Då "pushas din ändring", indexet ger skenet av att ha rensats och du är tillbaka vid din senaste commit. Nu kan du göra din lilla ändring, spara ändringen och göra en commit
git commit -a -m "did small change"
För att "poppa fram" din stora ändring och applicera den på din lilla ändring kör
git stash apply
"stash"-operationer går att stacka (så du kan trixa ännu mer om du vill) så för att undvika överraskningar i framtiden rensar vi stacken enligt
git stash clear
Dessa båda kommandon kan utföra samtidigt genom kommandot
git stash pop
"stash" är också användbart när man vill byta mellan brancher i samma träd utan att commita först (det smutsiga indexet följer annars med när man gör checkout).
Körsbärsplockning
[redigera]Säg att du skapat en ny branch och gjort en serie ändringar. I vårt fall har vi branchen "exp_more_questions" där vi gjort två commits, en ändring som frågar efter personens ålder och en som frågar efter var personen bor. Det resulterande programmet ser ut enligt
#!/usr/bin/python while 1: name = raw_input("What is your name? ") if name == "": break print "Hello " + name age = raw_input("What is your age? ") print age + " ... hey, that's not very old" city = raw_input("Where do you live? ") print city + " is really a nice place"
Loggen ser ut enligt
commit f374134012fe631863ef582b7b6ff7d57491224e Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 29 17:49:13 2008 +0200 added city question commit d26e573707da7d39528bd5b1ec59d114420327c3 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 29 17:47:05 2008 +0200 added age question commit 043e861919d386499a7c0df8a847352f8c8b36b5 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 03:19:25 2008 +0200 Fixade bug som skrev ut Hello när programmet avslutades commit f6c4c95a4a66c600cfdea15c0696199a9482d99e Author: Inge Glid <ingeglid@nosuchmail.com> Date: Mon Jun 16 03:06:05 2008 +0200 Hälsar och frågar nu i en loop commit 2adc0443929fe09111a37ab66573db20415985f0 Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:59:43 2008 +0200 Nu frågar programmet efter användarens namn och skrivet ut en hälsning commit db16eeb9c48d0b67e496e59fbaca154d0ffc02fb Author: Inge Glid <ingeglid@nosuchmail.com> Date: Sun Jun 15 15:32:10 2008 +0200 Vår första commit
Nu vill vi återföra modifikationerna till huvudbranchen, dock vill vi inte ha med ändringen som ger en fråga om åldern (det anses ofta vara en oartig fråga) och bara behålla stadsfrågan. I ett sådant litet program skulle vi mycket väl kunna göra pull på hela programmet och sedan manuellt radera åldersfrågan men GIT tillhandahåller en kraftfullare lösning: "cherry-picking". Det låter användaren plocka ändringar ifrån en viss commit och applicera dem på den aktuella branchen. För att applicera commit f374 på master kör vi
git checkout master git cherry-pick f374
Nu svarar GIT
Auto-merged hello.py CONFLICT (content): Merge conflict in hello.py Automatic cherry-pick failed. After resolving the conflicts, mark the corrected paths with 'git add <paths>' or 'git rm <paths>' and commit the result. When commiting, use the option '-c f374134' to retain authorship and message.
vi öppnar hello.py och ser vad konflikten gäller. hello.py ser ut enligt
#!/usr/bin/python while 1: name = raw_input("What is your name? ") if name == "": break print "Hello " + name <<<<<<< HEAD:hello.py ======= age = raw_input("What is your age? ") print age + " ... hey, that's not very old" city = raw_input("Where do you live? ") print city + " is really a nice place" >>>>>>> f374134... added city question:hello.py
Anledningen till att GIT protesterar är att GIT tror att åldersfrågan är en nödvändig förändring till stadsfrågan, då den direkt ansluter till kodstycket. För att lösa konflikten tar vi manuellt bort den kod inom konfliktblocket vi inte vill ha (inklusive själva blockmarkeringarna). Resultatet ser ut enligt
#!/usr/bin/python while 1: name = raw_input("What is your name? ") if name == "": break print "Hello " + name city = raw_input("Where do you live? ") print city + " is really a nice place"
Nu gör vi
git add hello.py git commit --no-edit -c f374134
för att slutföra konfliktlösningen och commita resultatet.
Om vi istället velat behålla åldersfrågan så hade vi inte fått någon konflikt eftersom ingen annan ändring gjorts i anslutning till det aktuella kodstycket. Vi kan ändå prova hur det hade blivit genom att ta bort den senaste commiten med
git reset --hard 043e git cherry-pick d26e
GIT svarar glatt
Finished one cherry-pick. Created commit 8330687: added age question 1 files changed, 2 insertions(+), 0 deletions(-)
Tittar vi på hello.py ges precis som väntat
#!/usr/bin/python while 1: name = raw_input("What is your name? ") if name == "": break print "Hello " + name age = raw_input("What is your age? ") print age + " ... hey, that's not very old"
Vi raderar den tillfälliga branchen med
git branch -D exp_more_questions
Rebasing (historikomskrivning)
[redigera]Rebase är ett mycket kraftfullt verktyg som kan användas på ändringar som BARA finns lokalt. Att det inte lämpar sig för publika ändringar beror på att rebase skriver om historiken och ändrar därigenom SHA-1:s för trädet. Huvudregeln är därför att bara rebasa inom ett intervall av commits som man ännu inte delgivit någon annan.
Interaktiv rebase
[redigera]För att göra en interaktiv rebase anger vi ett SHA-1 som från den nuvarande commiten definierar det intervall vi vill "rebasa" inom.
git rebase -i db16eeb9c48d0b67
öppar upp en texteditor enligt
pick f6c4c95 Hälsar och frågar nu i en loop pick 043e861 Fixade bug som skrev ut Hello när programmet avslutades pick 8330687 added age question pick d607386 added title # Rebase db16eeb..d607386 onto f6c4c95 # # Commands: # p, pick = use commit # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. #
Här kan vi ändra ordningen på commits genom att flytta runt rader. Vi kan ta bort rader för att radera commits. Vi kan också ändra "pick" till "edit" för att röra oss tillbaka i historiken och ändra i någon commit, eller infoga nya commits mellan två existerande commits. Ändrar man "pick" till "squash" slår man ihop flera commits till en commit.
Man bör vara försiktig när man gör rebase. Gör man fel kan man förlora eller förstöra delar av historiken. Innan man gör en rabase är det därför lämpligt att skapa en ny branch som man säkert kan "leka i". Anta att vi jobbar i master
git checkout -b ny_branch_att_rebasa_i
Därefter gör man sin rebase. Går något galet så tar man bort resultatet och går tillbaka till master enligt
git checkout master git branch -D ny_branch_att_rebasa_i
Om resultatet däremot blir bra kan man istället ta bort den gamla branchen och byta namn på sin nya branch
git branch -D master git branch -m master
Pull rebase
[redigera]Gör man "pull" från en server och man samtidigt har egna ändringar skapas en "merge" i historiken. Kör man ofta "pull" blir det väldigt många bågar och grenar i historiken vilket kan ses som rörigt och fult.
git pull --rebase
Löser problemet genom att först "lyfta av" dina egna ändringar från historiken, därefter fylla på från källan därifrån man hämtar ändringar och slutligen åter lägga på dina egna ändringar. Resultatet är en linjär historik. Kommandot kan köras hur många gånger som helst, men fungerar bara ifall dina ändringar ännu inte publicerats.