Î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.
Cuprins
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:
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.
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.
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.