Git Reset vs Revert vs Rebase

În acest articol, veți afla despre diferite moduri de a juca cu commit-uri în Git.

În calitate de dezvoltator, ați avea de mai multe ori astfel de situații în care ați fi dorit să reveniți la una dintre comiterile anterioare, dar nu știți cum să faceți asta. Și chiar dacă cunoașteți comenzile Git, cum ar fi resetare, revenire, rebase, nu sunteți conștient de diferențele dintre ele. Deci, să începem și să înțelegem ce sunt git reset, revert și rebase.

Resetare Git

Git reset este o comandă complexă și este folosită pentru a anula modificările.

Vă puteți gândi la git reset ca la o funcție de derulare. Cu git reset, puteți sări între diferite comiteri. Există trei moduri de rulare a unei comenzi git reset: –soft, –mixed și –hard. În mod implicit, comanda git reset folosește modul mixt. Într-un flux de lucru git reset, trei mecanisme interne de management ale git intră în imagine: HEAD, zona de staging (index) și directorul de lucru.

Directorul de lucru este locul în care lucrați în prezent, este locul în care sunt prezente fișierele dvs. Folosind o comandă git status, puteți vedea ce toate fișierele/folderele sunt prezente în directorul de lucru.

Zona de staging (Index) este locul unde git urmărește și salvează toate modificările din fișiere. Modificările salvate sunt reflectate în directorul .git. Folosiți git add „nume fișier” pentru a adăuga fișierul în zona de pregătire. Și ca și înainte, când rulați git status, veți vedea ce fișiere sunt prezente în zona de staging.

Ramura actuală din Git este denumită HEAD. Se referă la ultima comitere, care a avut loc în ramura curentă de plată. Este tratat ca un pointer pentru orice referință. Odată ce plătiți în altă filială, HEAD se mută și în noua filială.

Permiteți-mi să vă explic cum funcționează git reset în modurile hard, soft și mixte. Modul Hard este folosit pentru a merge la commit-ul punctat, directorul de lucru este populat cu fișiere ale acelui comit, iar zona de staging este resetată. În resetarea soft, doar indicatorul este schimbat la commit-ul specificat. Fișierele tuturor commit-urilor rămân în directorul de lucru și în zona de staging înainte de resetare. În modul mixt (implicit), indicatorul și zona de pregătire sunt resetate.

Git Reset Hard

Scopul git hard reset este de a muta HEAD la commit-ul specificat. Va elimina toate comitările cu care sa întâmplat după comiterea specificată. Această comandă va schimba istoricul de comitere și va indica comiterea specificată.

În acest exemplu, voi adăuga trei fișiere noi, le voi confirma și apoi voi efectua o resetare completă.

După cum puteți vedea din comanda de mai jos, chiar acum, nu este nimic de comis.

$ 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

Acum, voi crea 3 fișiere și voi adăuga conținut la ele.

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

Adăugați aceste fișiere în depozitul existent.

$ git add file*

Când executați din nou comanda de stare, aceasta va reflecta noile fișiere pe care tocmai le-am creat.

$ 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

Înainte de a comite, permiteți-mi să vă arăt, în prezent am un jurnal de 3 comite în Git.

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

Acum, mă voi angaja în depozit.

$ 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

Dacă fac ls-files, veți vedea că noile fișiere au fost adăugate.

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

Când rulez comanda log în git, am 4 comiteri, iar HEAD indică cea mai recentă comitere.

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

Dacă merg și șterg manual fișierul1.txt și fac o stare git, va afișa mesajul că modificările nu sunt pregătite pentru comitere.

$ 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")

Acum, voi rula comanda de resetare hard.

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

Dacă verific din nou starea, voi descoperi că nu există nimic de comis și fișierul pe care l-am șters a revenit în depozit. Rollback-ul s-a întâmplat deoarece după ștergerea fișierului, nu m-am comis, așa că, după o resetare completă, a revenit la starea anterioară.

$ 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

Dacă verific jurnalul lui git, așa va arăta.

$ 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

Scopul hard reset-ului este de a indica comiterea specificată și de a actualiza directorul de lucru și zona de staging. Permiteți-mi să vă arăt încă un exemplu. În prezent, vizualizarea commit-urilor mele arată mai jos:

  Cum să utilizați Wiki încorporat din Microsoft Teams

Aici, voi rula comanda cu HEAD^, ceea ce înseamnă că vreau să resetez la comiterea anterioară (un comit înapoi).

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

Puteți vedea că indicatorul de cap s-a schimbat acum la 0db602e de la d69950b.

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

Dacă verificați jurnalul, commit-ul lui d69950b a dispărut, iar capul indică acum 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

Dacă rulați fișierele ls, puteți vedea fișierul 1.txt, fișierul 2.txt și fișierul 3.txt nu mai sunt în depozit, deoarece acel commit și fișierul său au fost eliminate după resetare hard.

$ git ls-files
demo
dummyfile
newfile

Git Soft Reset

În mod similar, acum vă voi arăta un exemplu de resetare soft. Luați în considerare, am adăugat din nou cele 3 fișiere așa cum am menționat mai sus și le-am comis. Jurnalul git va apărea așa cum se arată mai jos. Puteți vedea că „resetarea soft” este cea mai recentă confirmare a mea, iar HEAD indică și asta.

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

Detaliile comiterii din jurnal pot fi văzute folosind comanda de mai jos.

$ 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

Acum, folosind resetarea soft, vreau să trec la una dintre comiterile mai vechi cu SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14

Pentru a face asta, voi rula comanda de mai jos. Trebuie să treceți mai mult de 6 caractere de început ale SHA, nu este necesar SHA complet.

$ git reset --soft 0db602e085a4

Acum, când rulez jurnalul git, pot vedea că HEAD a fost resetat la commit-ul pe care l-am specificat.

$ 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

Dar diferența aici este că fișierele commit-ului (aa400858aab3927e79116941c715749780a59fc9) unde am adăugat 3 fișiere sunt încă în directorul meu de lucru. Nu au fost șterse. De aceea, ar trebui să utilizați o resetare soft și nu o resetare completă. Nu există niciun risc de a pierde fișierele în modul soft.

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

Git Revert

În Git, comanda revert este folosită pentru a efectua o operație de revenire, adică pentru a anula unele modificări. Este similar cu comanda de resetare, dar singura diferență aici este că efectuați un nou commit pentru a reveni la un anumit commit. Pe scurt, este corect să spunem că comanda git revert este un commit.

  Stabiliți obiective minime de cuvinte atunci când scrieți povestiri scurte sau romane

Comanda Git revert nu șterge nicio dată în timpul efectuării operației de revenire.

Să presupunem că adaug 3 fișiere și efectuez o operație git commit pentru exemplul de retur.

$ 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

Jurnalul va afișa noul commit.

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

Acum aș dori să revin la una dintre comiterile mele anterioare, să spunem – „59c86c9 new commit”. Aș rula comanda de mai jos.

$ git revert 59c86c9

Aceasta va deschide un fișier, veți găsi detaliile commit-ului la care încercați să reveniți și puteți da un nume noului dvs. commit aici, apoi salvați și închideți fișierul.

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

După ce salvați și închideți fișierul, aceasta este rezultatul pe care îl veți obține.

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

Acum, pentru a face modificările necesare, spre deosebire de resetare, revenirea a efectuat încă o nouă comitere. Dacă verificați din nou jurnalul, veți găsi un nou commit din cauza operațiunii de revenire.

$ 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

Jurnalul Git va avea tot istoricul comiterilor. Dacă doriți să eliminați commit-urile din istoric, atunci revenirea nu este o alegere bună, dar dacă doriți să mențineți modificările commit-urilor în istoric, atunci retur este comanda potrivită în loc de resetare.

Git Rebase

În Git, rebase este modul de a muta sau de a combina comiterile unei ramuri peste alta. Ca dezvoltator, nu mi-aș crea caracteristicile pe ramura principală într-un scenariu real. Aș lucra pe propria mea ramură (o „ramură caracteristică”), iar când am câteva comiteri în ramura mea caracteristică cu caracteristica adăugată, aș dori apoi să o mut în ramura principală.

Rebase poate fi uneori puțin confuz de înțeles, deoarece este foarte asemănător cu o îmbinare. Scopul îmbinării și rebazării ambelor este de a lua commit-urile din ramura mea de caracteristici și de a le pune pe o ramură principală sau orice altă ramură. Luați în considerare, am un grafic care arată astfel:

Să presupunem că lucrați în echipă cu alți dezvoltatori. În acest caz, vă puteți imagina că acest lucru ar putea deveni foarte complex atunci când aveți o grămadă de alți dezvoltatori care lucrează la diferite ramuri de caracteristici și au fuzionat mai multe modificări. Devine confuz de urmărit.

  Social Somn Căutare inversă de imagini: explorați lumea digitală

Deci, aici rebase va ajuta. De data aceasta, în loc să fac o fuziune git, voi face o rebase, în care vreau să iau cele două comite-uri ale mele de ramuri caracteristice și să le mut în ramura principală. O rebază va lua toate comiterile mele din ramura caracteristică și le va muta deasupra comiterilor ramurilor principale. Deci, în culise, git duplică ramurile de caracteristică comise pe ramura principală.

Această abordare vă va oferi un grafic curat în linie dreaptă, cu toate comitările la rând.

Vă permite să urmăriți cu ușurință ce commit-uri au mers unde. Vă puteți imagina dacă sunteți într-o echipă cu mulți dezvoltatori, toate commit-urile sunt încă la rând. Deci, este foarte ușor de urmărit chiar dacă aveți mulți oameni care lucrează la același proiect în același timp.

Lasă-mă să-ți arăt asta practic.

Așa arată acum ramura mea principală. Are 4 comite.

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

Voi rula comanda de mai jos pentru a crea și a comuta la o nouă ramură numită caracteristică, iar această ramură va fi creată din a doua comitere, adică 59c86c9

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

Dacă verificați jurnalul în ramura caracteristică, acesta are doar 2 comiteri care provin de la master (linia principală).

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

Voi crea caracteristica 1 și o voi trimite în ramura caracteristică.

(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

Voi crea încă o caracteristică, și anume, caracteristica 2, în ramura caracteristică și o voi confirma.

(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

Acum, dacă verificați jurnalul ramului de caracteristici, are două noi comiteri, pe care le-am executat mai sus.

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

Acum vreau să adaug aceste două caracteristici noi la ramura principală. Pentru asta, voi folosi comanda rebase. Din ramura caracteristică, voi rebaza față de ramura principală. Ceea ce va face acest lucru este că îmi va ancora din nou ramura caracteristică față de cele mai recente modificări.

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

Acum voi merge mai departe și voi verifica ramura principală.

(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)

Și, în sfârșit, refaceți ramura principală față de ramura mea caracteristică. Acest lucru va lua acele două noi comite pe ramura mea de caracteristici și le va reda deasupra ramurii mele principale.

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

Acum, dacă verific jurnalul de pe ramura principală, pot vedea că cele două commit-uri ale ramurii mele de caracteristici au fost adăugate cu succes la ramura mea principală.

(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

Acesta a fost totul despre comenzile de resetare, revenire și rebase în Git.

Concluzie

Acesta a fost totul despre comenzile de resetare, revenire și rebase în Git. Sper că acest ghid pas cu pas a fost de ajutor. Acum, știți cum să vă jucați cu comiterile dvs. conform nevoilor, folosind comenzile menționate în articol.