Git: Difference between revisions
mNo edit summary |
mNo edit summary |
||
(58 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
__NOTOC__ | __NOTOC__ | ||
Denna artikel beskriver några kommandon och användarfall med [http://www.gitscm.org/ | Denna artikel beskriver några kommandon och användarfall med [http://www.gitscm.org/ git]. | ||
__TOC__ | __TOC__ | ||
Line 53: | Line 52: | ||
Din klon med namnet dir kommer nu inte innehålla något workspace. | Din klon med namnet dir kommer nu inte innehålla något workspace. | ||
== | == Rensa workspace == | ||
Efter en del arbete kommer ditt workspace innehålla versionshanterade, ändrade men också genererade och backup-filer. En del av de icke-versionshanterade filerna listas med {{Ic|git status}}, men en del filer ignoreras via en .gitignore fil. För att rensa hela ditt workspace från alla icke-versionshanterade inklusive ignorerade filer, gå till toppen av repositoryt och kör: | |||
{{Cmd|git clean -fdx}} | {{Cmd|git clean -fdx}} | ||
Använd -n optionen för att endast lista vilka filer som skulle ha raderats. | |||
== | == Versionshantera, komitta och sluta versionshantera förändringar == | ||
=== | === Versionshantera förändringar === | ||
För att addera en eller flera filer till git, kör: | |||
{{Cmd|git add <pattern>}} | {{Cmd|git add <pattern>}} | ||
Om en fil redan versionshanteras, kommer kommandot att addera förändringar till index. Om du vill addera alla gjorda förändringar till index, kör kommandot: | |||
{{Cmd|git add -u}} | {{Cmd|git add -u}} | ||
=== Commit | === Commit:a förändringar === | ||
För att commit:a förändringar redan adderade till index, kör: | |||
{{Cmd|git commit -m "Commit message"}} | {{Cmd|git commit -m "Commit message"}} | ||
Om man vill commit:a alla ändringar som är gjorda i redan versionshanterade filer, men ej adderade till index, kör kommandot: | |||
{{Cmd|git commit -am "Commit message"}} | {{Cmd|git commit -am "Commit message"}} | ||
=== | === Sluta versionshantera förändringar === | ||
För att ta bort en eller flera filer från workspace och index, kör kommandot: | |||
{{Cmd|git rm <pattern>}} | {{Cmd|git rm <pattern>}} | ||
Filerna kommer att tas bort från repositoryt när du commit:ar till repositoryt. | |||
== Diff | == Diff == | ||
=== Diff | === Diff:a workspace mot index === | ||
För att lista förändringar du har gjort i workspace, men som inte än är adderade till index, kör kommandot: | |||
{{Cmd|git diff}} | {{Cmd|git diff}} | ||
För att lista förändringar mellan ditt index och HEAD, dvs versionen du ser i repositoryt, kör kommandot: | |||
{{Cmd|git diff --cached}} | {{Cmd|git diff --cached}} | ||
Om du vill se alla dina icke-commit:ade förändringar (både adderade till index eller inte), kör kommandot: | |||
{{Cmd|git diff HEAD}} | {{Cmd|git diff HEAD}} | ||
==== | ==== Använda meld som grafiskt diff-verktyg ==== | ||
För att använda meld som diff-verktyg när man kör kommandot {{Ic|git difftool -g}} kör följande kommandon: | |||
{{ | {{Cmd|git config --global diff.tool meld|git config --global difftool.prompt false}} | ||
Man kan nu få upp grafiska jämförelser mellan versioner m.m. genom kommandot: | |||
{{Cmd|git difftool}} | |||
Ersätt {{Ic|git diff}} med {{Ic|git difftool}} i exemplen ovan. En diff med meld kan se ut så här: | |||
[[File:meld-diff1.png|500px]] | |||
(Äldre versionen visas till vänster och den nya till höger.) | |||
=== Diff:a commits === | |||
Antag att vi har följande historia: | |||
{{Bc|<nowiki> | {{Bc|<nowiki> | ||
* 2634685 2012-12-18 | Commit 4 (HEAD, master) [Peter Kerwien] | * 2634685 2012-12-18 | Commit 4 (HEAD, master) [Peter Kerwien] | ||
Line 114: | Line 116: | ||
</nowiki>}} | </nowiki>}} | ||
För att visa alla förändringar mellan commit 2 och 3, kör: | |||
{{Cmd|git diff b61568c d0afcbd}} | {{Cmd|git diff b61568c d0afcbd}} | ||
Du kan också köra kommandot: | |||
{{Cmd|git diff HEAD~3 HEAD~1}} | {{Cmd|git diff HEAD~3 HEAD~1}} | ||
== | == Välja revision == | ||
=== | === Släkt-referenser === | ||
Antag att vi har följande historia: | |||
{{Bc|<nowiki> | {{Bc|<nowiki> | ||
* 5b38862 2013-01-16 | Commit 5 (HEAD, master) [Peter Kerwien] | * 5b38862 2013-01-16 | Commit 5 (HEAD, master) [Peter Kerwien] | ||
Line 136: | Line 137: | ||
</nowiki>}} | </nowiki>}} | ||
Istället för att ange hela hashen för att välja version, kan man ange släkt-referenser genom att addera ^ eller ~ efter versionen. HEAD^ betyder den första föräldern till HEAD (=9940a50). Commit:en 9940a50 har två föräldrar, därför väljer 9940a50^ den föräldern som finns på nuvarande branch. Om vi är på master så kommer 9940a50^ välja commit:en f7935db. 9940a50^2 kommer välja den andre föräldern, i detta fall fc796ce. Man kan också lägga till flera ^ efter varandra. HEAD^^ kommer välja commit f7935db. | |||
~ | ~ däremot betyder alltid den första föräldern av en commit. Så följande exempel väljer alltid samma commit: | ||
* HEAD^ och HEAD~ | |||
* HEAD^^^ och HEAD~3 | |||
HEAD~2 betyder "första föräldern till första föräldern", så 9940a50~2 väljer commit:en dc53825. Detta är inte samma sak som 9940a50^2. | |||
Man kan kombinera dessa två, t.ex. HEAD~^2. Detta betyder "den andra föräldern till den första föräldern till HEAD", dvs commit:en fc796ce. | |||
== | == Ångra och ändra == | ||
{{Note| | {{Note|Ändra inte eller ta bort commit:s som du redan har delat med andra. Det är bara säkert att ändra historien om det bara påverkar dig själv.}} | ||
=== | === Ångra ändringar som inte har adderats till index === | ||
För att ångra ändringar som inte har adderats till index, kör kommandot: | |||
{{Cmd|<nowiki>git checkout -- <file></nowiki>}} | {{Cmd|<nowiki>git checkout -- <file></nowiki>}} | ||
=== | === Ångra ändringar som har adderats till index === | ||
För att ångra ändringar som har adderats till index, kör: | |||
{{Cmd|<nowiki>git reset HEAD <file></nowiki>}} | {{Cmd|<nowiki>git reset HEAD <file></nowiki>}} | ||
Reset kommandot återställer index till vad som pekas ut av HEAD. Reset kommandot återståller inte workspace. Så workspace kan fortfarande innehålla oönskade ändringar. | |||
=== | === Rätta senaste commit === | ||
Om du upptäcker att någonting saknas i den senaste commit:en och du vill inte göra en ny, då kan du rätta till ditt misstag med kommandot: | |||
{{Cmd|git commit --amend -m "..."}} | {{Cmd|git commit --amend -m "..."}} | ||
Du måste dock först addera vad du saknade till index innan du kör kommandot ovan. | |||
=== | === Ångra en commit === | ||
För att ångra en commit kan vi skapa en commit som tar bort dom förändringar som gjordes i den oönskade commit:en. För att ånga den senaste gjorda commit:en kör kommandot: | |||
{{Cmd|git revert HEAD}} | {{Cmd|git revert HEAD}} | ||
Om du vill ångra någon annan commit, ersätt HEAD med hashen. Använd optionen --no-edit om du vill acceptera standard commit meddelandet för en revert. | |||
=== | === Ta bort en commit på en branch === | ||
När man ångrar en commit med {{Ic|git revert}} kommer både den felaktiga och återställningen synas i historien. Om man vill ångra commit:en och radera den från historien kan man flytta HEAD pekaren tillbaka till commit:en före den felaktiga och börja om från början. Antag att man har en historia som ser ut så här: | |||
{{Bc| | {{Bc| | ||
<nowiki>* e5f1c95 2012-12-10 | Another good commit (HEAD, master) [Peter Kerwien] | <nowiki>* e5f1c95 2012-12-10 | Another good commit (HEAD, master) [Peter Kerwien] | ||
Line 178: | Line 182: | ||
* 4b732d0 2012-12-10 | Initial commit [Peter Kerwien] | * 4b732d0 2012-12-10 | Initial commit [Peter Kerwien] | ||
</nowiki>}} | </nowiki>}} | ||
Om man vill slänga bort dom 3 senaste commit:erna kan man flytta HEAD till commit 4b732d0 med kommandot: | |||
{{Cmd|git reset --hard 4b732d0|output=HEAD is now at 4b732d0 Initial commit}} | {{Cmd|git reset --hard 4b732d0|output=HEAD is now at 4b732d0 Initial commit}} | ||
När man sen genomför en ny commit, kommer historien se ut så här: | |||
{{Bc| | {{Bc| | ||
<nowiki>* 40ec614 2012-12-10 | The best commit ever (HEAD, master) [Peter Kerwien] | <nowiki>* 40ec614 2012-12-10 | The best commit ever (HEAD, master) [Peter Kerwien] | ||
Line 187: | Line 190: | ||
}} | }} | ||
{{Ic|git reset --hard}} | {{Ic|git reset --hard}} kommer även radera ev. icke-commit:ade ändringar i workspace. Om du vill spara alla förändringar (oavsett om de adderats till index eller inte), använd istället --soft optionen. De commit:s som blev slängda kommer fortfarande finnas kvar tills man städar repositoryt. Man kommer åt dessa commit:s via deras hash eller taggar. Man kan köra kommandot {{Ic|git reflog}} för att se var HEAD varit den senaste tiden. | ||
== Branch == | == Branch == | ||
=== | === Skapa och byta branch === | ||
Om man vill skapa och byta till en branch som heter test, kör kommandot: | |||
{{Cmd|git checkout -b test}} | {{Cmd|git checkout -b test}} | ||
Man kan också specifiera en annan branchnings punkt än HEAD via: | |||
{{Cmd|git checkout -b test tag|hash}} | {{Cmd|git checkout -b test <tag>}} | ||
Eller: | |||
{{Cmd|git checkout -b test <hash>}} | |||
=== | === Lista brancher === | ||
För att lista alla lokala brancher, kör: | |||
{{Cmd|git branch}} | {{Cmd|git branch}} | ||
Den aktuella branchen är markerad med *. Om man också vill se remote brancher, kör: | |||
{{Cmd|git branch --all}} | {{Cmd|git branch --all}} | ||
Om man bara vill lista alla lokala brancher som börjar på te, kör kommandot: | |||
{{Cmd|git branch --list te*}} | {{Cmd|git branch --list te*}} | ||
=== | === Växla mellan branch:er === | ||
Det är väldigt enkelt att växla mellan branch:er, kör bara kommandot: | |||
{{Cmd|git checkout <branch name>}} | {{Cmd|git checkout <branch name>}} | ||
Git | Git kommer att varna och stoppa dig om du har förändringar i workspace som inte är commit:ade. | ||
=== | === Byta namn på en branch === | ||
För att döpa om branch:en test till dev, kör kommandot: | |||
{{Cmd|git branch -m test dev}} | {{Cmd|git branch -m test dev}} | ||
=== | === Radera en branch === | ||
För att radera en branch som heter test, kör: | |||
{{Cmd|git branch -d test}} | {{Cmd|git branch -d test}} | ||
Git | Git kommer varna dig om branch:en inte har merge:ats ordentligt till annan branch. För att radera den trots detta, kör kommandot: | ||
{{Cmd|git branch -D test}} | {{Cmd|git branch -D test}} | ||
=== | === Följa en lokal branch i ett annat repository === | ||
Två användare har klonat samma repository (helloworld.git). Användare A skapar en lokal branch som heter test: | |||
{{Cmd|git checkout -b test}} | {{Cmd|git checkout -b test}} | ||
Sen skapar A en ändring och commit:ar den till sitt repository: | |||
{{Cmd|git commit - | {{Cmd|git commit -am "Commit made on test branch"}} | ||
Nu vill B följa denna branch. B måste då först lägga till As repository som en remote: | |||
{{Cmd|git remote add <local name> <url>}} | {{Cmd|git remote add <local name> <url>}} | ||
I detta exempel kommer B kalla As repository för hello_a och URL:en är en absolut sökväg till repositoryt: | |||
{{Cmd|git remote add hello_a /home/ | {{Cmd|git remote add hello_a /home/a/git/helloworld}} | ||
Visa detaljer om hello_a med kommandot: | |||
{{Cmd|git remote show hello_a}} | {{Cmd|git remote show hello_a}} | ||
{{Bc|1= | {{Bc|1= | ||
* remote hello_a | * remote hello_a | ||
Fetch URL: /home/ | Fetch URL: /home/a/git/helloworld | ||
Push URL: /home/ | Push URL: /home/a/git/helloworld | ||
HEAD branch: test | HEAD branch: test | ||
Remote branches: | Remote branches: | ||
Line 250: | Line 254: | ||
}} | }} | ||
Innan B kan följa test branch:en, måste B hämta heads, taggar, och objekt från As repository: | |||
{{Cmd|git fetch hello_a}} | {{Cmd|git fetch hello_a}} | ||
{{Bc|1= | {{Bc|1= | ||
Line 257: | Line 261: | ||
remote: Total 3 (delta 2), reused 0 (delta 0) | remote: Total 3 (delta 2), reused 0 (delta 0) | ||
Unpacking objects: 100% (3/3), done. | Unpacking objects: 100% (3/3), done. | ||
From /home/ | From /home/a/git/helloworld | ||
* [new branch] master -> hello_a/master | * [new branch] master -> hello_a/master | ||
* [new branch] test -> hello_a/test | * [new branch] test -> hello_a/test | ||
}} | }} | ||
B | B kan nu skapa en lokal branch som B också kallar test som följer As test branch: | ||
{{Cmd|git branch --track test hello_a/test|output=Branch test set up to track remote branch test from hello_a.}} | {{Cmd|git branch --track test hello_a/test|output=Branch test set up to track remote branch test from hello_a.}} | ||
Byt till test branchen: | |||
{{Cmd|git checkout test}} | {{Cmd|git checkout test}} | ||
== Merge == | == Merge == | ||
=== | === Olika typer av merge i git === | ||
I följande exempel har vi gjort 2 commit:s på en branch som heter test: | |||
[[Image:git-merge-before.png]] | [[Image:git-merge-before.png]] | ||
==== | ==== Ingen merge behövs (standard) ==== | ||
Om ingen commit har gjorts på master branch:en sen test skapades, kommer git göra en s.k. fast-forward merge om vi merge:ar test till master: | |||
{{Cmd|git merge test}} | |||
{{Bc|1= | |||
<nowiki>Updating e124053..8a48fa7 | |||
Fast-forward | |||
Makefile | 21 +++++++++++++++++++++ | |||
1 file changed, 21 insertions(+) | |||
create mode 100644 Makefile | |||
</nowiki>}} | |||
[[Image:git-merge-ff.png]] | [[Image:git-merge-ff.png]] | ||
Git bara flyttar HEAD framåt. Så alla commit:s vi har gjort på test branch:en kommer "flyttas" till master. Om vi pushar till origin kommer vi push:a två commit:s. | |||
==== | ==== Ingen merge behövs men med optionen --no-ff ==== | ||
Om ingen commit har gjorts på master branch:en sen test skapades, kommer git göra en s.k. fast-forward merge om vi merge:ar test till master. Men i detta fall använder vi --no-ff optionen: | |||
{{Cmd|git merge --no-ff test}} | |||
{{Bc|1= | |||
<nowiki> | |||
Merge made by the 'recursive' strategy. | |||
Makefile | 21 +++++++++++++++++++++ | |||
1 file changed, 21 insertions(+) | |||
create mode 100644 Makefile | |||
</nowiki>}} | |||
[[Image:git-merge-no-ff.png]] | [[Image:git-merge-no-ff.png]] | ||
Git | Git skapar nu en merge-commit på master. | ||
{{Note| | {{Note|Om vi push:ar master till origin, kommer vi inte bara push:a denna merge-commit, utan vi kommer push:a tre commit:s.}} | ||
==== Merge | ==== Merge behövs ==== | ||
Antag att någon har commit:at till master efter att vi branch:ade: | |||
[[Image:git-merge-needed.png]] | [[Image:git-merge-needed.png]] | ||
I detta fall måste git göra en vanlig merge, så vi behöver inte ange --no-ff optionen: | |||
{{Cmd|git merge test}} | |||
{{Bc|1= | |||
<nowiki> | |||
Merge made by the 'recursive' strategy. | |||
Makefile | 21 +++++++++++++++++++++ | |||
1 file changed, 21 insertions(+) | |||
create mode 100644 Makefile | |||
</nowiki>}} | |||
[[Image:git-merge.png]] | [[Image:git-merge.png]] | ||
Git | Git skapar nu en merge-commit på master. | ||
{{Note| | {{Note|Om vi push:ar master till origin, kommer vi inte bara push:a denna merge-commit, utan vi kommer push:a tre commit:s.}} | ||
=== | === Lösa merge-konflikter med meld === | ||
För att använda meld som grafisk merge-verktyg, kör följande kommandon: | |||
{{Cmd|git mergetool}} | |||
{{Cmd|git config --global merge.tool meld|git config --global merge.conflictstyle diff3|git config --global mergetool.prompt false}} | |||
Exempel: Efter en merge från test branch:en till master får vi följande utskrift: | |||
{{Bc| | {{Bc| | ||
Auto-merging main.c | Auto-merging main.c | ||
CONFLICT (content): Merge conflict in main.c | CONFLICT (content): Merge conflict in main.c | ||
Auto-merging | Auto-merging .gitignore | ||
Automatic merge failed; fix conflicts and then commit the result. | Automatic merge failed; fix conflicts and then commit the result. | ||
}} | }} | ||
Starta grafisk merge med meld: | |||
{{Cmd|git mergetool}} | {{Cmd|git mergetool}} | ||
Varje fil med konflikter kommer öppnas i meld. Meld-fönstret är uppdelat i 3 delar, från vänster till höger har vi: | |||
* | three parts. From left to right we have: | ||
* | * Versionen från master branch:en | ||
* | * Merge resultatet | ||
* Versionen från test branch:en | |||
[[Image:meld-merge1.png|600px]] | [[Image:meld-merge1.png|600px]] | ||
Lös merge:n genom att välja in ändringar antingen från vänster eller höger till vårt resultat i mitten. Du kan också editera koden i mitten för att skapa rätt merge resultat. Börja med att fixa alla icke-konflikter genom att i meld välja Changes => Merge all non-conflicting. TBD:Detta kan git/meld gör automatiskt med andra inställingar. | |||
[[Image:meld-merge2.png|600px]] | |||
Lös sedan den kvarvarande konflikten genom att välja ändringen från test branch:en. | |||
[[Image:meld-merge3.png|600px]] | |||
Spara filen och stäng meld. Nu är alla konflikter lösta och vi kan commit:a merge-resultatet till master. | |||
== Rebase == | == Rebase == | ||
Rebase | Rebase är ett sätt att framåt-porta dina commit:s till en nyare HEAD. Antag att vi har skapat 2 commit:s på en branch som heter test. Efter att vi branch:at så har någon annan gjort en ny commit på master: | ||
[[Image:git-rebase-before.png]] | [[Image:git-rebase-before.png]] | ||
Istället för att merga:a från master till test, vi kan rebase:a våra 2 commit:s. När man är på test branch:en, kör kommandot: | |||
{{Cmd|git rebase master}} | {{Cmd|git rebase master}} | ||
I detta exempel uppstår inga merge-konflikter, så git kommer automatiskt göra rebase:en åt oss: | |||
{{Bc|1= | {{Bc|1= | ||
First, rewinding head to replay your work on top of it... | First, rewinding head to replay your work on top of it... | ||
Applying: | Applying: Add Makefile | ||
Applying: | Applying: Minor edits in Makefile | ||
}} | }} | ||
Våra 2 commit:s har nu blivit modifierade och baseras nu på den nya HEAD på master. | |||
[[Image:git-rebase-after.png]] | [[Image:git-rebase-after.png]] | ||
{{Warning| | {{Warning|Gör inte rebase på commit:s som du push:at till delat repository eller på branch som du delar med annan användare!}} | ||
Men en rebase på en lokal branch är att föredra framför en merge, eftersom du kommer skapa en renare historia. Det spelar ingen roll om du merge:ar eller rebase:ar, varje konflikt måste lösas ändå. Om vi nu merge:ar till master, så kommer git default att göra en fast-forward merge. | |||
== Cherry-pick == | == Cherry-pick == | ||
=== Enkel cherry-picking utan konflikt === | |||
Om man vill merge:a commit:s från en branch till en annan, och vill exakt kunna peka ut enskilda commit:s som ska tas med, då kan man göra en sk. cherry-pick. Antag att vi har följande historia: | |||
{{Bc|<nowiki> | {{Bc|<nowiki> | ||
Line 372: | Line 405: | ||
</nowiki>}} | </nowiki>}} | ||
Vi vill nu applicera commit f39ba2f på vår test branch. För att göra det, byt till test branch:en och kör kommandot: | |||
{{Cmd|git cherry-pick f39ba2f}} | {{Cmd|git cherry-pick f39ba2f}} | ||
Line 380: | Line 413: | ||
</nowiki>}} | </nowiki>}} | ||
Historien vill nu se ut så här: | |||
{{Bc|<nowiki> | {{Bc|<nowiki> | ||
Line 393: | Line 426: | ||
</nowiki>}} | </nowiki>}} | ||
Notera att commit f39ba2f har hashen 81d9476 på test branch:en. | |||
=== | === Multipla cherry-picking med konflikt === | ||
Under cherry-picking, kan konflikter uppstå som måste lösas. I detta exempel kommer vi cherry-pick:a två commit:s, där den första kommer att ha konflikt med våra commit:s på test branch:en. Antag att vi har följande historia: | |||
{{Bc|<nowiki> | {{Bc|<nowiki> | ||
Line 408: | Line 441: | ||
</nowiki>}} | </nowiki>}} | ||
Byt till test branch:en och cherry-pick:a commit:s 413565e och fdb65d7. Den första kommer ha konflikter med commit e108d4a: | |||
{{Cmd|git cherry-pick 413565e fdb65d7}} | {{Cmd|git cherry-pick 413565e fdb65d7}} | ||
Line 418: | Line 451: | ||
}} | }} | ||
Lös konflikterna och commit:a merge resultatet. Nu kan vi återuppta cherry-picking med kommandot: | |||
{{Cmd|git cherry-pick --continue}} | {{Cmd|git cherry-pick --continue}} | ||
{{Bc|<nowiki> | {{Bc|<nowiki> | ||
Line 426: | Line 459: | ||
</nowiki>}} | </nowiki>}} | ||
Nu ser vår historia ut så här: | |||
{{Bc|<nowiki> | {{Bc|<nowiki> | ||
Line 439: | Line 472: | ||
</nowiki>}} | </nowiki>}} | ||
Vi har nu applicerat de två commit:sen och deras nya hashvärden på branch:en är bfc1ad9 respektive 9eac083. | |||
== Squash == | == Squash == | ||
När man gör en push kommer ev. flera commit:s att push:as. Det är inte alltid man vill att detta ska ske, eftersom man kanske har många commit:s på en lokal utvecklingsbranch. När man push:ar till en centralt repository kommer alla dessa commit:s att bli synliga för alla andra som klonar repositoryt. Om man istället vill push:a en feature som en enda kommit så kan man använda sig av squash:ing. En squash kan skapa en ny commit av flera andra commit:s. | |||
Antag att vi har utvecklat en feature på en branch som heter test. Allt är rebase:at till senaste commit på master: | |||
[[Image:git-squash-1.png]] | [[Image:git-squash-1.png]] | ||
Skapa en ny branch från master som heter test-squash (samma branch punkt som test branchen): | |||
{{Cmd|git checkout -B test-squash master}} | {{Cmd|git checkout -B test-squash master}} | ||
Merga:a alla commit:s från test, men tryck ihop dom till en enda commit: | |||
{{Cmd|git merge --squash test}} | {{Cmd|git merge --squash test}} | ||
Commit | Commit:a till test-squash: | ||
{{Cmd|git commit -am " | {{Cmd|git commit -am "Squash commits on test"}} | ||
Vi har nu skapat en enda commit på test-squash branch:en som innehåller summan av alla commit:s gjorda på test branch:en: | |||
[[Image:git-squash-2.png]] | [[Image:git-squash-2.png]] | ||
Byt till master branch:en och merge:a från test-squash (fast-forward merge): | |||
{{Cmd|git checkout master|git merge test-squash}} | {{Cmd|git checkout master|git merge test-squash}} | ||
[[Image:git-squash-3.png]] | [[Image:git-squash-3.png]] | ||
Om vi nu push:ar master till origin/master kommer endast en commit att adderas. | |||
== Terminologi == | |||
== | |||
{| class="wikitable sortable" border="1" cellpadding="2" cellspacing="0" | {| class="wikitable sortable" border="1" cellpadding="2" cellspacing="0" | ||
!|Term | !|Term | ||
!class="unsortable"| | !class="unsortable"|Beskrivning | ||
|- | |- | ||
| Bare repository | | Bare repository | ||
| | | Ett git repository utan workspace. Ett repository där du inte kan arbeta med filerna som versionshanteras. | ||
|- | |- | ||
| | | Klon | ||
| | | En kopia av ett repository. En klon innehåller normalt alla versioner av repot. | ||
|- | |- | ||
| | | Workspace | ||
| | | Arean där du kan jobba med alla filer. Det är här man kan editera, skapa nya filer och commit:a sina ändringar. Den delen av ett vanligt repo som inte ligger i .git katalogen. | ||
|- | |- | ||
| HEAD | | HEAD | ||
| | | En pekare som pekar ut den just nu valda versionen av repositoryt. | ||
|- | |- | ||
| Staged | | Staged | ||
| | | (Saknar bra svensk översättning). Adderad till index men inte commit:ad. | ||
|- | |- | ||
| Cached | | Cached | ||
| | | (Saknar bra svenska översättning). Se staged. | ||
|- | |- | ||
| | | Versionshanterad fil | ||
| | | En fil i workspace som är adderad och versionshanterad i git repositoryt. | ||
|- | |- | ||
| | | Icke-versionshanterad fil | ||
| | | En fil i workspace som inte är adderad och versionshanterad i git repositoryt. | ||
|- | |- | ||
| Index | | Index | ||
| | | Innehåller alla förändringar i versionshanterade filer som kommer commit:as när man kör kommandot git commit. | ||
|} | |} | ||
[[Category:Guide]] |
Latest revision as of 12:38, 27 September 2020
Denna artikel beskriver några kommandon och användarfall med git.
Inställningar
Git inställningar kan var global eller per repository (sparade under .git mappen i ett repository). Globala inställningar är sparade i filen ~/.gitconfig. Det går att läsa och editera filen ~/.gitconfig manuellt, eller använda kommandot git config --global. Några exempel hur man sätter, tar bort och läser inställningar:
Vem är du?
Ställ in namn och email adress:
Pager
Du kan välja vilken 'pager' (t.ex. more, less, cat) Git ska använda. Kör detta kommando om du vill att Git ska använda cat:
Snyggare log
För att skapa alias i Git, som t.ex. att skriva ut en kompakt och snygg log med kommandot git hist, kör kommandot:
Vi använder tformat istället för format för att få med ett avslutande 'carriage return' ifall du använder cat som din pager. Utskriften från git hist kommer att se ut så här:
* 40ec614 2012-12-10 | The best commit ever (HEAD, master) [Peter Kerwien] * 4b732d0 2012-12-10 | Initial commit [Peter Kerwien]
Repository
Skapa ett repository
För att skapa ett repository i en icke-existerande katalog, kör:
Eller om du vill skapa ett repository i nuvarande katalog:
Båda kommandona kommer skapa en dold katalog som heter .git. Dessa repositoryn kan också innehålla filerna som man jobbar med dvs ett 'workspace'. Om du vill skapa ett repository som ska fungera som ett centralt repository eller dela mellan flera användare och alla ska kunna pusha till repositoryt så måste man skapa ett s.k. bare repository. Ett bare repository saknar workspace och alla git-filer ligger synliga direkt i repositoryt och inte i en katalog som heter .git. För att skapa ett bare repository, kör::
Namnkonventionen är att bare repositorys slutar med ändelsen .git i namnet.
Klona ett repository
För att klona ett repository, dvs skapa en kopia av alla dess versioner, kör:
Det spelar ingen roll om du klonar ett vanligt eller bare repository, du kommer få en klon med ett workspace. Men om du vill klona utan ett workspace, kör kommandot:
Din klon med namnet dir kommer nu inte innehålla något workspace.
Rensa workspace
Efter en del arbete kommer ditt workspace innehålla versionshanterade, ändrade men också genererade och backup-filer. En del av de icke-versionshanterade filerna listas med git status, men en del filer ignoreras via en .gitignore fil. För att rensa hela ditt workspace från alla icke-versionshanterade inklusive ignorerade filer, gå till toppen av repositoryt och kör:
Använd -n optionen för att endast lista vilka filer som skulle ha raderats.
Versionshantera, komitta och sluta versionshantera förändringar
Versionshantera förändringar
För att addera en eller flera filer till git, kör:
Om en fil redan versionshanteras, kommer kommandot att addera förändringar till index. Om du vill addera alla gjorda förändringar till index, kör kommandot:
Commit:a förändringar
För att commit:a förändringar redan adderade till index, kör:
Om man vill commit:a alla ändringar som är gjorda i redan versionshanterade filer, men ej adderade till index, kör kommandot:
Sluta versionshantera förändringar
För att ta bort en eller flera filer från workspace och index, kör kommandot:
Filerna kommer att tas bort från repositoryt när du commit:ar till repositoryt.
Diff
Diff:a workspace mot index
För att lista förändringar du har gjort i workspace, men som inte än är adderade till index, kör kommandot:
För att lista förändringar mellan ditt index och HEAD, dvs versionen du ser i repositoryt, kör kommandot:
Om du vill se alla dina icke-commit:ade förändringar (både adderade till index eller inte), kör kommandot:
Använda meld som grafiskt diff-verktyg
För att använda meld som diff-verktyg när man kör kommandot git difftool -g kör följande kommandon:
Man kan nu få upp grafiska jämförelser mellan versioner m.m. genom kommandot:
Ersätt git diff med git difftool i exemplen ovan. En diff med meld kan se ut så här:
(Äldre versionen visas till vänster och den nya till höger.)
Diff:a commits
Antag att vi har följande historia:
* 2634685 2012-12-18 | Commit 4 (HEAD, master) [Peter Kerwien] * d0afcbd 2012-12-18 | Commit 3 [Peter Kerwien] * aaa2574 2012-12-18 | Commit 2 [Peter Kerwien] * b61568c 2012-12-18 | Initial commit [Peter Kerwien]
För att visa alla förändringar mellan commit 2 och 3, kör:
Du kan också köra kommandot:
Välja revision
Släkt-referenser
Antag att vi har följande historia:
* 5b38862 2013-01-16 | Commit 5 (HEAD, master) [Peter Kerwien] * 9940a50 2013-01-16 | Commit 4 [Peter Kerwien] |\ | * fc796ce 2013-01-16 | Commit on test (test) [Peter Kerwien] * | f7935db 2013-01-16 | Commit 3 [Peter Kerwien] |/ * dc53825 2013-01-16 | Commit 2 [Peter Kerwien] * bea9676 2013-01-16 | Initial commit [Peter Kerwien]
Istället för att ange hela hashen för att välja version, kan man ange släkt-referenser genom att addera ^ eller ~ efter versionen. HEAD^ betyder den första föräldern till HEAD (=9940a50). Commit:en 9940a50 har två föräldrar, därför väljer 9940a50^ den föräldern som finns på nuvarande branch. Om vi är på master så kommer 9940a50^ välja commit:en f7935db. 9940a50^2 kommer välja den andre föräldern, i detta fall fc796ce. Man kan också lägga till flera ^ efter varandra. HEAD^^ kommer välja commit f7935db.
~ däremot betyder alltid den första föräldern av en commit. Så följande exempel väljer alltid samma commit:
- HEAD^ och HEAD~
- HEAD^^^ och HEAD~3
HEAD~2 betyder "första föräldern till första föräldern", så 9940a50~2 väljer commit:en dc53825. Detta är inte samma sak som 9940a50^2.
Man kan kombinera dessa två, t.ex. HEAD~^2. Detta betyder "den andra föräldern till den första föräldern till HEAD", dvs commit:en fc796ce.
Ångra och ändra
Ångra ändringar som inte har adderats till index
För att ångra ändringar som inte har adderats till index, kör kommandot:
Ångra ändringar som har adderats till index
För att ångra ändringar som har adderats till index, kör:
Reset kommandot återställer index till vad som pekas ut av HEAD. Reset kommandot återståller inte workspace. Så workspace kan fortfarande innehålla oönskade ändringar.
Rätta senaste commit
Om du upptäcker att någonting saknas i den senaste commit:en och du vill inte göra en ny, då kan du rätta till ditt misstag med kommandot:
Du måste dock först addera vad du saknade till index innan du kör kommandot ovan.
Ångra en commit
För att ångra en commit kan vi skapa en commit som tar bort dom förändringar som gjordes i den oönskade commit:en. För att ånga den senaste gjorda commit:en kör kommandot:
Om du vill ångra någon annan commit, ersätt HEAD med hashen. Använd optionen --no-edit om du vill acceptera standard commit meddelandet för en revert.
Ta bort en commit på en branch
När man ångrar en commit med git revert kommer både den felaktiga och återställningen synas i historien. Om man vill ångra commit:en och radera den från historien kan man flytta HEAD pekaren tillbaka till commit:en före den felaktiga och börja om från början. Antag att man har en historia som ser ut så här:
* e5f1c95 2012-12-10 | Another good commit (HEAD, master) [Peter Kerwien] * e491e6d 2012-12-10 | Good commit [Peter Kerwien] * ba30da7 2012-12-10 | Bad commit [Peter Kerwien] * 4b732d0 2012-12-10 | Initial commit [Peter Kerwien]
Om man vill slänga bort dom 3 senaste commit:erna kan man flytta HEAD till commit 4b732d0 med kommandot:
När man sen genomför en ny commit, kommer historien se ut så här:
* 40ec614 2012-12-10 | The best commit ever (HEAD, master) [Peter Kerwien] * 4b732d0 2012-12-10 | Initial commit [Peter Kerwien]
git reset --hard kommer även radera ev. icke-commit:ade ändringar i workspace. Om du vill spara alla förändringar (oavsett om de adderats till index eller inte), använd istället --soft optionen. De commit:s som blev slängda kommer fortfarande finnas kvar tills man städar repositoryt. Man kommer åt dessa commit:s via deras hash eller taggar. Man kan köra kommandot git reflog för att se var HEAD varit den senaste tiden.
Branch
Skapa och byta branch
Om man vill skapa och byta till en branch som heter test, kör kommandot:
Man kan också specifiera en annan branchnings punkt än HEAD via:
Eller:
Lista brancher
För att lista alla lokala brancher, kör:
Den aktuella branchen är markerad med *. Om man också vill se remote brancher, kör:
Om man bara vill lista alla lokala brancher som börjar på te, kör kommandot:
Växla mellan branch:er
Det är väldigt enkelt att växla mellan branch:er, kör bara kommandot:
Git kommer att varna och stoppa dig om du har förändringar i workspace som inte är commit:ade.
Byta namn på en branch
För att döpa om branch:en test till dev, kör kommandot:
Radera en branch
För att radera en branch som heter test, kör:
Git kommer varna dig om branch:en inte har merge:ats ordentligt till annan branch. För att radera den trots detta, kör kommandot:
Följa en lokal branch i ett annat repository
Två användare har klonat samma repository (helloworld.git). Användare A skapar en lokal branch som heter test:
Sen skapar A en ändring och commit:ar den till sitt repository:
Nu vill B följa denna branch. B måste då först lägga till As repository som en remote:
I detta exempel kommer B kalla As repository för hello_a och URL:en är en absolut sökväg till repositoryt:
Visa detaljer om hello_a med kommandot:
* remote hello_a Fetch URL: /home/a/git/helloworld Push URL: /home/a/git/helloworld HEAD branch: test Remote branches: master new (next fetch will store in remotes/hello_a) test new (next fetch will store in remotes/hello_a) Local ref configured for 'git push': master pushes to master (up to date)
Innan B kan följa test branch:en, måste B hämta heads, taggar, och objekt från As repository:
remote: Counting objects: 5, done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 2), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From /home/a/git/helloworld * [new branch] master -> hello_a/master * [new branch] test -> hello_a/test
B kan nu skapa en lokal branch som B också kallar test som följer As test branch:
Byt till test branchen:
Merge
Olika typer av merge i git
I följande exempel har vi gjort 2 commit:s på en branch som heter test:
Ingen merge behövs (standard)
Om ingen commit har gjorts på master branch:en sen test skapades, kommer git göra en s.k. fast-forward merge om vi merge:ar test till master:
Updating e124053..8a48fa7 Fast-forward Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Makefile
Git bara flyttar HEAD framåt. Så alla commit:s vi har gjort på test branch:en kommer "flyttas" till master. Om vi pushar till origin kommer vi push:a två commit:s.
Ingen merge behövs men med optionen --no-ff
Om ingen commit har gjorts på master branch:en sen test skapades, kommer git göra en s.k. fast-forward merge om vi merge:ar test till master. Men i detta fall använder vi --no-ff optionen:
Merge made by the 'recursive' strategy. Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Makefile
Git skapar nu en merge-commit på master.
Merge behövs
Antag att någon har commit:at till master efter att vi branch:ade:
I detta fall måste git göra en vanlig merge, så vi behöver inte ange --no-ff optionen:
Merge made by the 'recursive' strategy. Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Makefile
Git skapar nu en merge-commit på master.
Lösa merge-konflikter med meld
För att använda meld som grafisk merge-verktyg, kör följande kommandon:
Exempel: Efter en merge från test branch:en till master får vi följande utskrift:
Auto-merging main.c CONFLICT (content): Merge conflict in main.c Auto-merging .gitignore Automatic merge failed; fix conflicts and then commit the result.
Starta grafisk merge med meld:
Varje fil med konflikter kommer öppnas i meld. Meld-fönstret är uppdelat i 3 delar, från vänster till höger har vi: three parts. From left to right we have:
- Versionen från master branch:en
- Merge resultatet
- Versionen från test branch:en
Lös merge:n genom att välja in ändringar antingen från vänster eller höger till vårt resultat i mitten. Du kan också editera koden i mitten för att skapa rätt merge resultat. Börja med att fixa alla icke-konflikter genom att i meld välja Changes => Merge all non-conflicting. TBD:Detta kan git/meld gör automatiskt med andra inställingar.
Lös sedan den kvarvarande konflikten genom att välja ändringen från test branch:en.
Spara filen och stäng meld. Nu är alla konflikter lösta och vi kan commit:a merge-resultatet till master.
Rebase
Rebase är ett sätt att framåt-porta dina commit:s till en nyare HEAD. Antag att vi har skapat 2 commit:s på en branch som heter test. Efter att vi branch:at så har någon annan gjort en ny commit på master:
Istället för att merga:a från master till test, vi kan rebase:a våra 2 commit:s. När man är på test branch:en, kör kommandot:
I detta exempel uppstår inga merge-konflikter, så git kommer automatiskt göra rebase:en åt oss:
First, rewinding head to replay your work on top of it... Applying: Add Makefile Applying: Minor edits in Makefile
Våra 2 commit:s har nu blivit modifierade och baseras nu på den nya HEAD på master.
Men en rebase på en lokal branch är att föredra framför en merge, eftersom du kommer skapa en renare historia. Det spelar ingen roll om du merge:ar eller rebase:ar, varje konflikt måste lösas ändå. Om vi nu merge:ar till master, så kommer git default att göra en fast-forward merge.
Cherry-pick
Enkel cherry-picking utan konflikt
Om man vill merge:a commit:s från en branch till en annan, och vill exakt kunna peka ut enskilda commit:s som ska tas med, då kan man göra en sk. cherry-pick. Antag att vi har följande historia:
* b5df0bb 2012-12-17 | Added main() header (HEAD, test) [Peter Kerwien] | * 12ad7c3 2012-12-17 | Whitespace edit in main.c (master) [Peter Kerwien] | * f39ba2f 2012-12-14 | Add some file headers [Peter Kerwien] | * 02d1638 2012-12-14 | Change hello message [Peter Kerwien] |/ * 0e1085d 2012-12-14 | Made some cleanup [Peter Kerwien] * 10213e2 2012-12-14 | Initial commit [Peter Kerwien]
Vi vill nu applicera commit f39ba2f på vår test branch. För att göra det, byt till test branch:en och kör kommandot:
[test 81d9476] Add some file headers 2 files changed, 4 insertions(+)
Historien vill nu se ut så här:
* 81d9476 2012-12-14 | Add some file headers (HEAD, test) [Peter Kerwien] * b5df0bb 2012-12-17 | Added main() header [Peter Kerwien] | * 12ad7c3 2012-12-17 | Whitespace edit in main.c (master) [Peter Kerwien] | * f39ba2f 2012-12-14 | Add some file headers [Peter Kerwien] | * 02d1638 2012-12-14 | Change hello message [Peter Kerwien] |/ * 0e1085d 2012-12-14 | Made some cleanup [Peter Kerwien] * 10213e2 2012-12-14 | Initial commit [Peter Kerwien]
Notera att commit f39ba2f har hashen 81d9476 på test branch:en.
Multipla cherry-picking med konflikt
Under cherry-picking, kan konflikter uppstå som måste lösas. I detta exempel kommer vi cherry-pick:a två commit:s, där den första kommer att ha konflikt med våra commit:s på test branch:en. Antag att vi har följande historia:
* e108d4a 2012-12-17 | Hello test! (HEAD, test) [Peter Kerwien] | * fdb65d7 2012-12-17 | Return EXIT_SUCCESS instead of 0 (master) [Peter Kerwien] | * 69e7150 2012-12-17 | Added argc & argv parameters to main() [Peter Kerwien] | * 413565e 2012-12-17 | Changed hello message [Peter Kerwien] |/ * 3ff2e68 2012-12-17 | Initial commit [Peter Kerwien]
Byt till test branch:en och cherry-pick:a commit:s 413565e och fdb65d7. Den första kommer ha konflikter med commit e108d4a:
error: could not apply 413565e... Changed hello message hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and commit the result with 'git commit'
Lös konflikterna och commit:a merge resultatet. Nu kan vi återuppta cherry-picking med kommandot:
$ git cherry-pick --continue [test 9eac083] Return EXIT_SUCCESS instead of 0 1 file changed, 2 insertions(+), 1 deletion(-)
Nu ser vår historia ut så här:
* 9eac083 2012-12-17 | Return EXIT_SUCCESS instead of 0 (HEAD, test) [Peter Kerwien] * bfc1ad9 2012-12-17 | Changed hello message [Peter Kerwien] * e108d4a 2012-12-17 | Hello test! [Peter Kerwien] | * fdb65d7 2012-12-17 | Return EXIT_SUCCESS instead of 0 (master) [Peter Kerwien] | * 69e7150 2012-12-17 | Added argc & argv parameters to main() [Peter Kerwien] | * 413565e 2012-12-17 | Changed hello message [Peter Kerwien] |/ * 3ff2e68 2012-12-17 | Initial commit [Peter Kerwien]
Vi har nu applicerat de två commit:sen och deras nya hashvärden på branch:en är bfc1ad9 respektive 9eac083.
Squash
När man gör en push kommer ev. flera commit:s att push:as. Det är inte alltid man vill att detta ska ske, eftersom man kanske har många commit:s på en lokal utvecklingsbranch. När man push:ar till en centralt repository kommer alla dessa commit:s att bli synliga för alla andra som klonar repositoryt. Om man istället vill push:a en feature som en enda kommit så kan man använda sig av squash:ing. En squash kan skapa en ny commit av flera andra commit:s.
Antag att vi har utvecklat en feature på en branch som heter test. Allt är rebase:at till senaste commit på master:
Skapa en ny branch från master som heter test-squash (samma branch punkt som test branchen):
Merga:a alla commit:s från test, men tryck ihop dom till en enda commit:
Commit:a till test-squash:
Vi har nu skapat en enda commit på test-squash branch:en som innehåller summan av alla commit:s gjorda på test branch:en:
Byt till master branch:en och merge:a från test-squash (fast-forward merge):
Om vi nu push:ar master till origin/master kommer endast en commit att adderas.
Terminologi
Term | Beskrivning |
---|---|
Bare repository | Ett git repository utan workspace. Ett repository där du inte kan arbeta med filerna som versionshanteras. |
Klon | En kopia av ett repository. En klon innehåller normalt alla versioner av repot. |
Workspace | Arean där du kan jobba med alla filer. Det är här man kan editera, skapa nya filer och commit:a sina ändringar. Den delen av ett vanligt repo som inte ligger i .git katalogen. |
HEAD | En pekare som pekar ut den just nu valda versionen av repositoryt. |
Staged | (Saknar bra svensk översättning). Adderad till index men inte commit:ad. |
Cached | (Saknar bra svenska översättning). Se staged. |
Versionshanterad fil | En fil i workspace som är adderad och versionshanterad i git repositoryt. |
Icke-versionshanterad fil | En fil i workspace som inte är adderad och versionshanterad i git repositoryt. |
Index | Innehåller alla förändringar i versionshanterade filer som kommer commit:as när man kör kommandot git commit. |