Czy mogę usunąć commit z Gita, ale zachować zmiany?

W jednej z moich gałęzi programistycznych wprowadziłem kilka zmian w mojej bazie kodowej. Zanim udało mi się ukończyć funkcje, nad którymi pracowałem, musiałem przełączyć moją bieżącą gałąź na master, aby demo niektórych funkcji. Ale samo użycie "Git checkOut master" zachowało zmiany, które również wprowadziłem w swojej gałęzi deweloperskiej, tym samym łamiąc część funkcjonalności w master. Więc to, co zrobiłem, to zatwierdzić zmiany w mojej gałęzi rozwoju z Komunikatem commit "tymczasowy commit", a następnie checkout mistrz dema.

Teraz, gdy skończyłem z demem I wróciłem do pracy nad moją gałęzią programistyczną, chciałbym usunąć "tymczasowy commit", który zrobiłem, zachowując jednocześnie wprowadzone zmiany. Czy to możliwe?

Author: Leniel Maccaferri, 2013-04-02

11 answers

To takie proste:

git reset HEAD^

Uwaga: niektóre powłoki traktują ^ jako znak specjalny (na przykład niektóre powłoki Windows lub ZSH z włączonym globbingiem ), więc być może będziesz musiał zacytować "HEAD^" w takich przypadkach.

git reset Bez --hard lub --soft przenosi HEAD do wskazanego commita, bez zmiany plików. HEAD^ odnosi się do (pierwszego) nadrzędnego commita bieżącego commita, który w Twoim przypadku jest commitem przed tymczasowym.

Zauważ, że inną opcją jest kontynuowanie pracy normalnie, a następnie w następnym punkcie zatwierdzania Uruchom:

git commit --amend [-m … etc]

Który zamiast edytuje najnowszy commit, mając taki sam efekt jak powyżej.

Zauważ, że to (jak w przypadku prawie każdej odpowiedzi Gita) może powodować problemy, jeśli już wypchnąłeś zły commit do miejsca, z którego ktoś inny mógł go wyciągnąć. Staraj się tego unikać

 1917
Author: Gareth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-29 13:41:45

Istnieją dwa sposoby radzenia sobie z tym. Co jest łatwiejsze zależy od twojej sytuacji

Reset

Jeśli commit, którego chcesz się pozbyć, był ostatnim commitem, a nie wykonałeś żadnej dodatkowej pracy, możesz po prostu użyć git-reset

git reset HEAD^

Przenosi Twoją gałąź z powrotem do commita tuż przed twoją obecną głową. Jednak w rzeczywistości nie zmienia to plików w roboczym drzewie. W rezultacie zmiany, które były w tym commicie, pojawiają się jako zmodyfikowane-to jak polecenie 'uncommit'. Mam na to pseudonim.

git config --global alias.uncommit 'reset HEAD^'

Wtedy możesz użyć git uncommit w przyszłości, aby utworzyć kopię zapasową jednego commita.

Zgniatanie

Zgniatanie commita oznacza połączenie dwóch lub więcej commitów w jeden. Robię to dość często. W Twoim przypadku masz już ukończoną funkcję, a następnie zakończysz ją i zatwierdzisz ponownie odpowiednim, trwałym Komunikatem zatwierdzającym.

git rebase -i <ref>

Mówię wyżej, ponieważ chcę to wyjaśnić może to być dowolna liczba commitów. Uruchom git log i znajdź commit, którego chcesz się pozbyć, skopiuj jego SHA1 i użyj go zamiast <ref>. Git przeniesie cię w interaktywny tryb rebase. Wyświetli wszystkie commity pomiędzy Twoim obecnym stanem a tym, co umieściłeś w miejscu <ref>. Więc jeśli <ref> jest 10 commitów temu, pokaże Ci wszystkie 10 commitów.

Przed każdym commitem pojawi się słowo pick. Znajdź commit, którego chcesz się pozbyć i zmień go z pick na fixup lub squash. Użycie fixup po prostu odrzuca, który zatwierdza wiadomość i łączy zmiany z jego bezpośrednim poprzednikiem na liście. Słowo kluczowe squash robi to samo, ale pozwala edytować komunikat commit nowo połączonego commit.

Zauważ, że commity będą ponownie zatwierdzane w kolejności, w jakiej pojawią się na liście po wyjściu z edytora. Jeśli więc utworzyłeś tymczasowy commit, wykonałeś inną pracę w tej samej gałęzi i ukończyłeś tę funkcję w późniejszym commicie, a następnie używając rebase pozwoli Ci to na ponowne sortowanie commitów i ich zgniatanie.

WARNING:

Rebasing modyfikuje historię-nie rób tego dla commitów, które już udostępniłeś innym programistom.

Stashing

W przyszłości, aby uniknąć tego problemu, rozważ użycie git stash do tymczasowego przechowywania niezatwierdzonych prac.

git stash save 'some message'

To zapisze Twoje bieżące zmiany na stronie listy skrytek. Powyżej jest najbardziej wyraźna wersja Komenda stash, pozwalająca na komentarz opisujący co ukrywasz. Możesz również po prostu uruchomić git stash i nic więcej, ale żadna wiadomość nie zostanie zapisana.

Możesz przeglądać swoją listę skrytek...

git stash list

To pokaże Ci wszystkie Twoje staszki, na jakich gałęziach zostały zrobione, wiadomość i początek każdej linii oraz identyfikator tego skrytki, który wygląda tak stash@{#} gdzie # jest jego pozycją w tablicy stosów.

Aby przywrócić skrytkę (która może być wykonane na dowolnej gałęzi, niezależnie od tego, gdzie pierwotnie został utworzony stash) po prostu uruchom...

git stash apply stash@{#}

Ponownie, tam # jest pozycja w tablicy stashes. Jeśli schowek, który chcesz przywrócić, znajduje się w pozycji 0 - to znaczy, jeśli był to najnowszy Schowek. Następnie możesz po prostu uruchomić polecenie bez podawania pozycji stash, git założy, że masz na myśli ostatnią: git stash apply.

Więc, na przykład, jeśli znajdę się pracując na niewłaściwej gałęzi - mogę uruchomić następujące Sekwencja poleceń.

git stash
git checkout <correct_branch>
git stash apply

W Twoim przypadku poruszałeś się po gałęziach trochę więcej, ale ten sam pomysł nadal obowiązuje.

Mam nadzieję, że to pomoże.
 220
Author: eddiemoya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 12:32:25

Myślę, że szukasz tego

git reset --soft HEAD~1

Wycofuje najnowszy commit, zachowując zmiany wprowadzone w tym commicie w inscenizacji.

 134
Author: Sudhanshu Jain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-23 02:38:40

Tak, możesz usunąć swój commit bez usuwania zmian:

git reset @~
 51
Author: DURGESH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-19 17:07:17

Szukasz albo git reset HEAD^ --soft albo git reset HEAD^ --mixed.

Istnieją 3 tryby polecenia reset, jak podano w docs:

git reset HEAD^ --soft

Cofnij git commit. Zmiany nadal istnieją w drzewie roboczym(folderze projektu) + indeksie (--cached)

git reset HEAD^ --mixed

Cofnij git commit + git add. Zmiany nadal istnieją w działającym drzewie

git reset HEAD^ --hard

Jakbyś nigdy nie wprowadził tych zmian w bazie kodowej. Zmiany zniknęły z pracujące drzewo.
 34
Author: Bar Horing Amir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-06 11:22:58

W moim przypadku, już przesunąłem się do repo. AUĆ!

Możesz przywrócić określony commit, zachowując zmiany w lokalnych plikach, wykonując:

git revert -n <sha>

W ten sposób udało mi się zachować potrzebne zmiany i usunąć commit, który został już wypchnięty.

 10
Author: Wim Feijen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-18 14:20:22

2020 prosty sposób:

git reset <commit_hash>

(hash commit ostatniego commita, który chcesz zachować).

Jeśli commit został wypchnięty, możesz wykonać :

git push -f

Zachowasz teraz niezakontraktowane zmiany lokalnie

 10
Author: Xys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-04 17:51:37

Dla tych, którzy używają zsh, musisz użyć:

git reset --soft HEAD\^

Wyjaśnione tutaj: https://github.com/robbyrussell/oh-my-zsh/issues/449

W przypadku, gdy URL stanie się martwy, ważną częścią jest:

Escape the ^ in your command

Możesz alternatywnie użyć HEAD~ , abyś nie musiał uciekać przed nim za każdym razem.

 9
Author: Greg Hilston,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Używanie git 2.9 (dokładnie 2.9.2.okna.1) git reset HEAD^ podpowiada więcej; nie wiem, czego tu oczekujemy. Proszę zapoznać się z poniższym zrzutem ekranu

Tutaj wpisz opis obrazka

Znaleziono inne rozwiązanie git reset HEAD~#numberOfCommits za pomocą którego możemy wybrać liczbę lokalnych commitów, które chcesz zresetować, zachowując swoje zmiany w stanie nienaruszonym. W związku z tym mamy możliwość odrzucenia wszystkich lokalnych commitów, jak również ograniczonej liczby lokalnych commitów.

Patrz poniżej zrzuty ekranu pokazujące git reset HEAD~1 w działanie: Tutaj wpisz opis obrazka

Tutaj wpisz opis obrazka

 3
Author: nkharche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-22 10:03:54

Jeszcze jeden sposób.

Dodaj commit na górze tymczasowego commita, a następnie wykonaj:

git rebase -i

Aby połączyć dwa commity w jeden (polecenie otworzy plik tekstowy z wyraźnymi instrukcjami, edytuje go).

 2
Author: Ruslan Osipov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-02 19:59:54

W niektórych przypadkach chcę tylko cofnąć zmiany w określonych plikach w pierwszym zatwierdzeniu, aby dodać je do drugiego zatwierdzania i mieć czystszy dziennik git.

W tym przypadku, to co robię jest następujące:

git checkout HEAD~1 <path_to_file_to_put_in_different_commit>
git add -u
git commit --amend --no-edit
git checkout HEAD@{1} <path_to_file_to_put_in_different_commit>
git commit -m "This is the new commit"

Oczywiście działa to dobrze nawet w środku rebase -i z opcją edycji na commit to split.

 1
Author: Louis Caron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-12 07:09:17