Git Reset vs Revert vs Rebase

I den här artikeln kommer du att lära dig om olika sätt att leka med commits i Git.

Som utvecklare skulle du ha stött på sådana situationer flera gånger där du skulle ha velat gå tillbaka till en av dina tidigare commits men inte säker på hur du gör det. Och även om du känner till Git-kommandona som reset, revert, rebase, är du inte medveten om skillnaderna mellan dem. Så låt oss komma igång och förstå vad git reset, revert och rebase är.

Git Reset

Git reset är ett komplext kommando och det används för att ångra ändringarna.

Du kan tänka på git-återställning som en återställningsfunktion. Med git-återställning kan du hoppa mellan olika commits. Det finns tre lägen för att köra ett git-återställningskommando: –soft, –mixed och –hard. Som standard använder git reset-kommandot det blandade läget. I ett arbetsflöde för återställning av git kommer tre interna hanteringsmekanismer för git in i bilden: HEAD, iscensättningsområde (index) och arbetskatalogen.

Arbetskatalogen är platsen där du för närvarande arbetar, det är platsen där dina filer finns. Med hjälp av ett git-statuskommando kan du se vilka alla filer/mappar som finns i arbetskatalogen.

Staging Area (Index) är där git spårar och sparar alla ändringar i filerna. De sparade ändringarna återspeglas i .git-katalogen. Du använder git add ”filnamn” för att lägga till filen till iscensättningsområdet. Och som tidigare, när du kör git-status, kommer du att se vilka filer som finns i uppställningsområdet.

Den nuvarande grenen i Git kallas HEAD. Det pekar på den senaste commit, som hände i den aktuella kassan. Den behandlas som en pekare för alla referenser. När du har betalat till en annan filial, flyttar HEAD också till den nya filialen.

Låt mig förklara hur git-återställning fungerar i hårda, mjuka och blandade lägen. Hårt läge används för att gå till den spetsiga commit, arbetskatalogen fylls med filer av den commit, och iscensättningsområdet återställs. Vid mjuk återställning ändras endast pekaren till angiven commit. Filerna för alla commits finns kvar i arbetskatalogen och mellanlagringsområdet innan återställningen. I blandat läge (standard) återställs både pekaren och mellanställningsområdet.

Git Reset Hard

Syftet med git hård återställning är att flytta HEAD till den specificerade commit. Det kommer att ta bort alla commits med hände efter den angivna commit. Detta kommando kommer att ändra commit-historiken och peka på den angivna commit.

I det här exemplet kommer jag att lägga till tre nya filer, commit dem och sedan utföra en hård återställning.

Som du kan se från kommandot nedan, just nu, finns det inget att begå.

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.

(use "git push" to publish your local commits)

nothing to commit, working tree clean

Nu kommer jag att skapa 3 filer och lägga till lite innehåll till det.

$ vi file1.txt
$ vi file2.txt
$ vi file3.txt

Lägg till dessa filer till det befintliga arkivet.

$ git add file*

När du kör statuskommandot igen kommer det att återspegla de nya filerna jag just skapade.

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.

(use "git push" to publish your local commits)

Changes to be committed:

(use "git restore --staged <file>..." to unstage)

new file:
file1.txt

new file:
file2.txt

new file:
file3.txt

Innan jag begår, låt mig visa dig, jag har för närvarande en logg över 3 commits i Git.

$ git log --oneline
0db602e (HEAD -> master) one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Nu kommer jag att förbinda mig till förvaret.

$ git commit -m 'added 3 files'
[master d69950b] added 3 files
3 files changed, 3 insertions(+)
create mode 100644 file1.txt
create mode 100644 file2.txt
create mode 100644 file3.txt

Om jag gör ls-filer kommer du att se att de nya filerna har lagts till.

$ git ls-files
demo
dummyfile
newfile
file1.txt
file2.txt
file3.txt

När jag kör log-kommandot i git har jag 4 commits, och HEAD pekar på den senaste commit.

$ git log --oneline
d69950b (HEAD -> master) added 3 files
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Om jag går och tar bort file1.txt manuellt och gör en git-status, kommer det att visa meddelandet att ändringarna inte är iscensatta för commit.

$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.

(use "git push" to publish your local commits)

Changes not staged for commit:

(use "git add/rm <file>..." to update what will be committed)

(use "git restore <file>..." to discard changes in working directory)

deleted:
file1.txt

no changes added to commit (use "git add" and/or "git commit -a")

Nu kommer jag att köra kommandot hård återställning.

$ git reset --hard
HEAD is now at d69950b added 3 files

Om jag kontrollerar statusen igen kommer jag att upptäcka att det inte finns något att begå, och filen jag tog bort har kommit tillbaka till förvaret. Återställningen har hänt eftersom jag inte commit efter att ha tagit bort filen, så efter en hård återställning gick den tillbaka till det tidigare tillståndet.

$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.

(use "git push" to publish your local commits)

nothing to commit, working tree clean

Om jag kollar loggen för git så kommer det se ut så här.

$ git log
commit d69950b7ea406a97499e07f9b28082db9db0b387 (HEAD -> master)
Author: mrgeek <[email protected]>
Date:
Mon May 17 19:53:31 2020 +0530

added 3 files

commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Author: mrgeek <[email protected]>
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:16:33 2020 +0530

test

Syftet med hård återställning är att peka på den specificerade commit och uppdatera arbetskatalogen och mellanlagringsområdet. Låt mig visa dig ytterligare ett exempel. För närvarande ser visualiseringen av mina åtaganden ut så här:

Här kommer jag att köra kommandot med HEAD^, vilket betyder att jag vill återställa till föregående commit (en commit tillbaka).

$ git reset --hard HEAD^
HEAD is now at 0db602e one more commit

Du kan se att huvudpekaren nu har ändrats till 0db602e från d69950b.

$ git log --oneline
0db602e (HEAD -> master) one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Om du kontrollerar loggen är commit för d69950b borta, och huvudet pekar nu på 0db602e SHA.

$ git log
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master)
Author: mrgeek <[email protected]>
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:16:33 2020 +0530

Test

Om du kör ls-filerna kan du se att file1.txt, file2.txt och files3.txt inte finns i förvaret längre eftersom den commit och dess fil togs bort efter den hårda återställningen.

$ git ls-files
demo
dummyfile
newfile

Git Soft Reset

På samma sätt kommer jag nu att visa dig ett exempel på en mjuk återställning. Tänk på att jag har lagt till de 3 filerna igen som nämnts ovan och begått dem. Git-loggen kommer att visas som visas nedan. Du kan se ”mjuk återställning” är min senaste commit, och HEAD pekar också på det.

$ git log --oneline
aa40085 (HEAD -> master) soft reset
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Detaljer om commit i loggen kan ses med kommandot nedan.

$ git log
commit aa400858aab3927e79116941c715749780a59fc9 (HEAD -> master)
Author: mrgeek <[email protected]>
Date:
Mon May 17 21:01:36 2020 +0530

soft reset

commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Author: mrgeek <[email protected]>
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:16:33 2020 +0530

test

Nu genom att använda den mjuka återställningen vill jag byta till en av de äldre commits med SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14

För att göra det kommer jag att köra kommandot nedan. Du måste klara mer än 6 starttecken i SHA, fullständig SHA krävs inte.

$ git reset --soft 0db602e085a4

Nu när jag kör git-loggen kan jag se att HEAD har återställts till den commit jag angav.

$ git log
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master)
Author: mrgeek <[email protected]>
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:16:33 2020 +0530

test

Men skillnaden här är att filerna för commit (aa400858aab3927e79116941c715749780a59fc9) där jag hade lagt till 3 filer finns fortfarande i min arbetskatalog. De har inte tagits bort. Det är därför du bör använda en mjuk återställning snarare än en hård återställning. Det finns ingen risk att förlora filerna i mjukt läge.

$ git ls-files
demo
dummyfile
file1.txt
file2.txt
file3.txt
newfile

Git Revert

I Git används revert-kommandot för att utföra en revert-operation, dvs för att återställa vissa ändringar. Det liknar reset-kommandot, men den enda skillnaden här är att du utför en ny commit för att gå tillbaka till en viss commit. Kort sagt, det är rättvist att säga att git revert-kommandot är en commit.

Git revert-kommandot tar inte bort någon data medan återställningsåtgärden utförs.

Låt oss säga att jag lägger till 3 filer och utför en git commit-operation för återställningsexemplet.

$ git commit -m 'add 3 files again'
[master 812335d] add 3 files again
3 files changed, 3 insertions(+)
create mode 100644 file1.txt
create mode 100644 file2.txt
create mode 100644 file3.txt

Loggen kommer att visa den nya commit.

$ git log --oneline
812335d (HEAD -> master) add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Nu skulle jag vilja återgå till en av mina tidigare commits, låt oss säga – ”59c86c9 new commit”. Jag skulle köra kommandot nedan.

$ git revert 59c86c9

Detta kommer att öppna en fil, du kommer att hitta detaljerna för den commit du försöker återgå till, och du kan ge din nya commit ett namn här och sedan spara och stänga filen.

Revert "new commit"

This reverts commit 59c86c96a82589bad5ecba7668ad38aa684ab323.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Your branch is ahead of 'origin/master' by 4 commits.
# (use "git push" to publish your local commits)
#
# Changes to be committed:
# modified: dummyfile

När du har sparat och stängt filen är det här utdata du kommer att få.

$ git revert 59c86c9
[master af72b7a] Revert "new commit"
1 file changed, 1 insertion(+), 1 deletion(-)

Nu för att göra de nödvändiga ändringarna, till skillnad från återställning, har revert utfört ytterligare en ny commit. Om du kontrollerar loggen igen, kommer du att hitta en ny commit på grund av återställningsoperationen.

$ git log --oneline
af72b7a (HEAD -> master) Revert "new commit"
812335d add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Git-loggen kommer att ha all historik över commits. Om du vill ta bort commiterna från historiken är revert inte ett bra val, men om du vill behålla commit-ändringarna i historiken är revert det lämpliga kommandot istället för reset.

Git Rebase

I Git är rebase sättet att flytta eller kombinera commits från en gren över en annan gren. Som utvecklare skulle jag inte skapa mina funktioner på mastergrenen i ett verkligt scenario. Jag skulle arbeta på min egen gren (en ’funktionsgren’), och när jag har några commits i min funktionsgren med funktionen tillagd, skulle jag vilja flytta den till huvudgrenen.

Rebase kan ibland vara lite förvirrande att förstå eftersom det är väldigt likt en merge. Målet med att slå samman och ombasera båda är att ta commits från min feature-gren och lägga dem till en master-gren eller någon annan gren. Tänk på att jag har en graf som ser ut så här:

Anta att du arbetar i ett team med andra utvecklare. I så fall kan du föreställa dig att det här kan bli riktigt komplext där du har ett gäng andra utvecklare som arbetar med olika funktionsgrenar, och de har slagit samman flera förändringar. Det blir förvirrande att spåra.

Så det är här rebase kommer att hjälpa. Den här gången, istället för att göra en git-fusion, kommer jag att göra en rebase, där jag vill ta mina två funktionsgren-commits och flytta dem till master-grenen. En rebase tar alla mina commits från feature-grenen och flyttar dem ovanpå master-gren-commits. Så, bakom kulisserna, duplicerar git funktionsgrenen som utförs på mastergrenen.

Detta tillvägagångssätt kommer att ge dig en ren rät linje med alla commits i rad.

Det gör det enkelt att spåra vilka commits som gick vart. Du kan föreställa dig om du är i ett team med många utvecklare, alla commits är fortfarande på rad. Så det är verkligen lätt att följa även om du har många som arbetar med samma projekt samtidigt.

Låt mig visa dig detta praktiskt.

Så här ser min mastergren ut just nu. Den har 4 commits.

$ git log --oneline
812335d (HEAD -> master) add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Jag kommer att köra kommandot nedan för att skapa och byta till en ny gren som heter feature, och denna gren kommer att skapas från den andra commit, dvs 59c86c9

(master)
$ git checkout -b feature 59c86c9
Switched to a new branch 'feature'

Om du kontrollerar loggen i funktionsgrenen har den bara 2 commits som kommer från mastern (huvudlinjen).

(feature)
$ git log --oneline
59c86c9 (HEAD -> feature) new commit
e2f44fc (origin/master, origin/HEAD) test

Jag kommer att skapa funktion 1 och överlåta den till funktionsgrenen.

(feature)
$ vi feature1.txt

(feature)
$ git add .
The file will have its original line endings in your working directory

(feature)
$ git commit -m 'feature 1'
[feature c639e1b] feature 1
1 file changed, 1 insertion(+)
create mode 100644 feature1.txt

Jag kommer att skapa ytterligare en funktion, dvs funktion 2, i funktionsgrenen och commit den.

(feature)
$ vi feature2.txt

(feature)
$ git add .
The file will have its original line endings in your working directory

(feature)
$ git commit -m 'feature 2'
[feature 0f4db49] feature 2
1 file changed, 1 insertion(+)
create mode 100644 feature2.txt

Om du nu kontrollerar loggen för funktionsgrenen har den två nya commits, som jag körde ovan.

(feature)
$ git log --oneline
0f4db49 (HEAD -> feature) feature 2
c639e1b feature 1
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Nu vill jag lägga till dessa två nya funktioner till mastergrenen. För det kommer jag att använda kommandot rebase. Från funktionsgrenen kommer jag att rebasera mot mastergrenen. Vad detta kommer att göra är att det kommer att återförankra min funktionsgren mot de senaste ändringarna.

(feature)
$ git rebase master
Successfully rebased and updated refs/heads/feature.

Nu ska jag gå vidare och kolla in masterfilialen.

(feature)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 3 commits.

(use "git push" to publish your local commits)

Och slutligen, rebasera mastergrenen mot min funktionsgren. Detta kommer att ta dessa två nya commits på min feature-gren och spela upp dem ovanpå min master-gren.

(master)
$ git rebase feature
Successfully rebased and updated refs/heads/master.

Om jag nu kontrollerar loggen på master-grenen kan jag se att de två commits av min features-gren har lagts till i min master-gren.

(master)
$ git log --oneline
766c996 (HEAD -> master, feature) feature 2
c036a11 feature 1
812335d add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Det handlade om att återställa, återställa och återställa kommandon i Git.

Slutsats

Det handlade om att återställa, återställa och återställa kommandon i Git. Jag hoppas att den här steg-för-steg-guiden var till hjälp. Nu vet du hur du ska leka med dina åtaganden efter behov med hjälp av kommandona som nämns i artikeln.