Resetowanie Git a przywracanie a zmiana bazy

Opublikowany: 2021-05-20

W tym artykule dowiesz się o różnych sposobach zabawy z zatwierdzeniami w Git.

Jako programista wielokrotnie napotykałbyś takie sytuacje, w których chciałbyś cofnąć się do jednego z poprzednich zatwierdzeń, ale nie wiesz, jak to zrobić. A nawet jeśli znasz polecenia Git, takie jak resetowanie, przywracanie, zmiana bazy, nie jesteś świadomy różnic między nimi. Zacznijmy więc i zrozum, czym są git reset, revert i rebase.

Resetowanie Gita

Git reset to złożone polecenie, które służy do cofania zmian.

Możesz myśleć o git reset jako o funkcji wycofywania. Dzięki git reset możesz przeskakiwać między różnymi zatwierdzeniami. Istnieją trzy tryby uruchamiania polecenia git reset: –soft, –mixed i –hard. Domyślnie polecenie git reset używa trybu mieszanego. W przepływie pracy git reset pojawiają się trzy wewnętrzne mechanizmy zarządzania git: HEAD , obszar przemieszczania (indeks) i katalog roboczy .

git reset - geekflare

Katalog roboczy to miejsce, w którym aktualnie pracujesz, jest to miejsce, w którym znajdują się Twoje pliki. Używając polecenia git status, możesz zobaczyć, jakie wszystkie pliki/foldery znajdują się w katalogu roboczym.

Obszar pomostowy (indeks) to miejsce, w którym git śledzi i zapisuje wszystkie zmiany w plikach. Zapisane zmiany są odzwierciedlane w katalogu .git. Używasz git add „nazwa pliku”, aby dodać plik do obszaru pomostowego. I tak jak poprzednio, kiedy uruchomisz git status, zobaczysz, które pliki są obecne w obszarze przemieszczania.

Bieżąca gałąź w Git jest określana jako HEAD. Wskazuje na ostatnie zatwierdzenie, które miało miejsce w bieżącej gałęzi kasy. Jest traktowany jako wskaźnik do dowolnego odniesienia. Po przejściu do innego oddziału HEAD również przenosi się do nowego oddziału.

Pozwólcie, że wyjaśnię, jak działa git reset w trybach twardych, miękkich i mieszanych. Tryb twardy jest używany do przejścia do wskazanego zatwierdzenia, katalog roboczy zostaje zapełniony plikami tego zatwierdzenia, a obszar przemieszczania zostaje zresetowany. W miękkim resecie tylko wskaźnik jest zmieniany na określone zatwierdzenie. Pliki wszystkich zatwierdzeń pozostają w katalogu roboczym i obszarze pomostowym przed zresetowaniem. W trybie mieszanym (domyślnie) wskaźnik i obszar przemieszczania zostają zresetowane.

Git Resetuj mocno

Celem git hard reset jest przeniesienie HEAD do określonego zatwierdzenia. Usunie wszystkie zatwierdzenia, które miały miejsce po określonym zatwierdzeniu. To polecenie zmieni historię zatwierdzeń i wskaże określone zatwierdzenie.

W tym przykładzie dodam trzy nowe pliki, zatwierdzę je, a następnie przeprowadzę twardy reset.

Jak widać z poniższego polecenia, w tej chwili nie ma nic do zatwierdzenia.

 $ 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

Teraz stworzę 3 pliki i dodam do nich trochę treści.

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

Dodaj te pliki do istniejącego repozytorium.

 $ git add file*

Po ponownym uruchomieniu polecenia status będzie ono odzwierciedlać nowe pliki, które właśnie utworzyłem.

 $ 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

Przed zatwierdzeniem pokażę ci, że obecnie mam dziennik 3 zatwierdzeń w Git.

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

Teraz zobowiązuję się do repozytorium.

 $ 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

Jeśli zrobię ls-files, zobaczysz, że nowe pliki zostały dodane.

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

Kiedy uruchamiam polecenie log w git, mam 4 zatwierdzenia, a HEAD wskazuje na ostatnie zatwierdzenie.

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

Jeśli pójdę i usunę plik file1.txt ręcznie i zrobię status git, pokaże się komunikat, że zmiany nie są przygotowane do zatwierdzenia.

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

Teraz uruchomię polecenie twardego resetu.

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

Jeśli ponownie sprawdzę status, stwierdzę, że nie ma nic do zatwierdzenia, a plik, który usunąłem, wrócił do repozytorium. Wycofanie nastąpiło, ponieważ po usunięciu pliku nie zatwierdziłem, więc po twardym resecie wrócił do poprzedniego stanu.

 $ 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

Jeśli sprawdzę log git, tak to będzie wyglądać.

 $ 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

Celem twardego resetu jest wskazanie określonego zatwierdzenia i zaktualizowanie katalogu roboczego i obszaru pomostowego. Pokażę jeszcze jeden przykład. Obecnie wizualizacja moich commitów wygląda jak poniżej:

ciężko

Tutaj uruchomię polecenie z HEAD^, co oznacza, że ​​chcę zresetować do poprzedniego zatwierdzenia (jedno zatwierdzenie z powrotem).

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

Widać, że wskaźnik głowy zmienił się teraz na 0db602e z d69950b.

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

ciężko 1

Jeśli sprawdzisz dziennik, zatwierdzenie d69950b zniknęło, a nagłówek wskazuje teraz na 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

Jeśli uruchomisz pliki ls, zobaczysz, że plik1.txt, plik2.txt i pliki3.txt nie znajdują się już w repozytorium, ponieważ zatwierdzenie i jego plik zostały usunięte po twardym resecie.

 $ git ls-files demo dummyfile newfile

Miękki reset Gita

Podobnie teraz pokażę przykład miękkiego resetu. Zastanów się, dodałem ponownie 3 pliki, jak wspomniano powyżej, i zatwierdziłem je. Dziennik git pojawi się, jak pokazano poniżej. Widać, że „miękki reset” jest moim ostatnim zatwierdzeniem i HEAD również na to wskazuje.

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

Szczegóły zatwierdzenia w dzienniku można zobaczyć za pomocą poniższego polecenia.

 $ 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

Teraz używając miękkiego resetu, chcę przełączyć się na jedno ze starszych zatwierdzeń z SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14

Aby to zrobić, uruchomię poniższe polecenie. Musisz przekazać więcej niż 6 początkowych znaków SHA, pełne SHA nie jest wymagane.

 $ git reset --soft 0db602e085a4

Teraz, gdy uruchamiam dziennik git, widzę, że HEAD został zresetowany do określonego przeze mnie zatwierdzenia.

 $ 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

Ale różnica polega na tym, że pliki zatwierdzenia (aa400858aab3927e79116941c715749780a59fc9), w których dodałem 3 pliki, nadal znajdują się w moim katalogu roboczym. Nie zostały usunięte. Dlatego powinieneś używać miękkiego resetu, a nie twardego resetu. W trybie miękkim nie ma ryzyka utraty plików.

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

Przywróć git

W Git polecenie przywracania służy do wykonywania operacji przywracania, tj. przywracania niektórych zmian. Jest podobny do polecenia resetowania, ale jedyną różnicą jest to, że wykonujesz nowe zatwierdzenie, aby wrócić do konkretnego zatwierdzenia. Krótko mówiąc, można powiedzieć, że polecenie git revert jest zatwierdzeniem.

Polecenie Git revert nie usuwa żadnych danych podczas wykonywania operacji przywracania.

Załóżmy, że dodaję 3 pliki i wykonuję operację zatwierdzenia git dla przykładu przywracania.

 $ 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

Dziennik pokaże nowe zatwierdzenie.

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

Teraz chciałbym wrócić do jednego z moich poprzednich commitów, powiedzmy – „59c86c9 new commit”. Uruchomiłbym poniższe polecenie.

 $ git revert 59c86c9

Spowoduje to otwarcie pliku, znajdziesz szczegóły zatwierdzenia, do którego próbujesz powrócić, i możesz nadać nazwę swojemu nowemu zatwierdzeniu tutaj, a następnie zapisać i zamknąć plik.

 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

Po zapisaniu i zamknięciu pliku otrzymasz wynik.

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

Teraz, aby wprowadzić niezbędne zmiany, w przeciwieństwie do resetowania, przywrócenie wykonało jeszcze jedno nowe zatwierdzenie. Jeśli ponownie sprawdzisz dziennik, znajdziesz nowe zatwierdzenie z powodu operacji przywracania.

 $ 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 odwróć

Dziennik Git będzie zawierał całą historię zmian. Jeśli chcesz usunąć zatwierdzenia z historii, przywrócenie nie jest dobrym wyborem, ale jeśli chcesz zachować zmiany w historii, przywróć jest odpowiednią komendą zamiast resetowania.

Zmiana bazy Gita

W Git rebase to sposób na przenoszenie lub łączenie zatwierdzeń jednej gałęzi z inną gałęzią. Jako programista nie tworzyłbym swoich funkcji w gałęzi master w rzeczywistym scenariuszu. Pracowałbym nad własną gałęzią („gałąź funkcji”), a kiedy mam kilka zatwierdzeń w gałęzi funkcji z dodaną funkcją, chciałbym przenieść ją do gałęzi głównej.

Zmiana bazy może czasami być nieco myląca, ponieważ jest bardzo podobna do łączenia. Celem połączenia i zmiany bazy jest pobranie zatwierdzeń z mojej gałęzi funkcji i umieszczenie ich w gałęzi master lub dowolnej innej gałęzi. Zastanów się, mam wykres, który wygląda tak:

git rebase

Załóżmy, że pracujesz w zespole z innymi programistami. W takim przypadku możesz sobie wyobrazić, że może to być naprawdę skomplikowane, gdy masz kilku innych programistów pracujących nad różnymi gałęziami funkcji, którzy łączą wiele zmian. Śledzenie staje się mylące.

I tu właśnie pomoże rebase. Tym razem zamiast scalania git, zrobię rebase, w którym chcę wziąć moje dwie zmiany gałęzi funkcji i przenieść je do gałęzi master. Rebase pobierze wszystkie moje zatwierdzenia z gałęzi funkcji i przeniesie je na górę zatwierdzeń gałęzi głównej. Tak więc za kulisami git duplikuje zatwierdzenia gałęzi funkcji na gałęzi master.

git rebase 1

Takie podejście da ci czysty, liniowy wykres ze wszystkimi zatwierdzeniami w rzędzie.

git odwróć 2

Ułatwia śledzenie, jakie zatwierdzenia i gdzie poszły. Możesz sobie wyobrazić, że jeśli jesteś w zespole z wieloma programistami, wszystkie zatwierdzenia są nadal w jednym rzędzie. Tak więc jest to naprawdę łatwe, nawet jeśli masz wiele osób pracujących nad tym samym projektem w tym samym czasie.

Pokażę ci to praktycznie.

Tak wygląda obecnie moja gałąź master. Ma 4 zatwierdzenia.

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

Uruchomię poniższe polecenie, aby utworzyć i przejść do nowej gałęzi o nazwie feature, a ta gałąź zostanie utworzona z drugiego zatwierdzenia, tj. 59c86c9

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

Jeśli sprawdzisz dziennik w gałęzi funkcji, ma tylko 2 zatwierdzenia pochodzące z mastera (głównej linii).

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

Stworzę funkcję 1 i przekażę ją do gałęzi funkcji.

 (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

Stworzę jeszcze jedną cechę, tj. cechę 2, w gałęzi funkcji i zatwierdzę ją.

 (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

Teraz, jeśli sprawdzisz dziennik gałęzi funkcji, ma ona dwa nowe zatwierdzenia, które wykonałem powyżej.

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

Teraz chcę dodać te dwie nowe funkcje do gałęzi master. W tym celu użyję polecenia rebase. Z gałęzi funkcji zmienię bazę względem gałęzi głównej. To, co to zrobi, to ponowne zakotwiczenie mojej gałęzi funkcji w stosunku do najnowszych zmian.

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

Teraz zamierzam przejść do kasy głównej gałęzi.

 (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 na koniec zmień bazę gałęzi master na moją gałąź funkcji. Spowoduje to zabranie tych dwóch nowych zatwierdzeń w mojej gałęzi funkcji i odtworzenie ich na mojej gałęzi głównej.

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

Teraz, jeśli sprawdzę dziennik w gałęzi master, widzę, że dwa zatwierdzenia mojej gałęzi features zostały pomyślnie dodane do gałęzi master.

 (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

To wszystko o poleceniach resetowania, przywracania i rebase w Git.

Wniosek

To wszystko o poleceniach resetowania, przywracania i rebase w Git. Mam nadzieję, że ten przewodnik krok po kroku był pomocny. Teraz wiesz, jak bawić się swoimi zatwierdzeniami zgodnie z potrzebą, używając poleceń wymienionych w artykule.