Jak naprawić zatwierdzenie do niewłaściwej gałęzi Git?


621

Właśnie zrobiłem idealnie dobre zobowiązanie do niewłaściwej gałęzi. Jak cofnąć ostatnie zatwierdzenie w mojej gałęzi master, a następnie wprowadzić te same zmiany i wprowadzić je do mojej gałęzi aktualizacji?

Odpowiedzi:


975

Jeśli nie wprowadziłeś jeszcze zmian, możesz także wykonać miękki reset:

git reset --soft HEAD^

Spowoduje to cofnięcie zatwierdzenia, ale przywróci zatwierdzone zmiany z powrotem do indeksu. Zakładając, że gałęzie są stosunkowo aktualne w stosunku do siebie, git pozwoli ci dokonać transakcji w drugim oddziale, po czym możesz po prostu zatwierdzić:

git checkout branch
git commit

Wadą jest to, że musisz ponownie wprowadzić komunikat zatwierdzenia.


10
zwróć uwagę, że miękki reset pozostawia zmiany wprowadzone i gotowe do zatwierdzenia. trochę się zdezorientowałem, gdy moje IDE nie pokazało, że pliki wróciły do ​​stanu zmodyfikowanego po miękkim resecie.
mtjhax

9
idealna poprawka, faktycznie miałem kilka zobowiązań, więc HEAD ^^ i bam wszystko jest sos
pablo

8
Dzięki. To mnie dwukrotnie uratowało. Jeśli gałęzie są nieco inne, po resecie i przed kasie może być konieczne ukrycie zmian przed przejściem do kolejnej gałęzi. Ponownie zastosuj skrytkę po kasie
Kirby,

17
Użytkownicy zsh: może się okazać, że musisz uciec ^ tak:git reset --soft HEAD\^
Stephen Fuhry

54
Jeśli dostaniesz Więcej? w wierszu poleceń systemu Windows użyj cudzysłowów, aby otoczyć HEAD ^ tak: git reset --soft "HEAD ^"
Nate Cook

140

4 lata spóźnienia na ten temat, ale może to być komuś pomocne.

Jeśli zapomniałeś utworzyć nowy oddział przed zatwierdzeniem i zatwierdzeniem wszystkiego na masterie, bez względu na to, ile zrobiłeś zatwierdzeń, poniższe podejście jest łatwiejsze:

git stash                       # skip if all changes are committed
git branch my_feature
git reset --hard origin/master
git checkout my_feature
git stash pop                   # skip if all changes were committed

Teraz masz gałąź master równą origin/masteri wszystkie nowe zatwierdzenia są włączone my_feature. Pamiętaj, że my_featurejest to oddział lokalny, a nie zdalny.


Dziękuję za odpowiedź. Teraz używam egit i zastanawiam się, czy mogę to zrobić, wykonując następujące czynności: 1) Zmień nazwę obecnego „master” na „my_feature”. 2) Odtwórz lokalnego „master” z „origin / master”. Nie jestem pewien, co robi egit pod maską dla tych operacji, ale wydaje się, że jest to realne rozwiązanie
mjj1409,

dlaczego połączenie możesz utworzyć gałąź bezpośrednio master, a następnie zresetować masterdo origin/master.
caesarsol

1
To jest najciekawsza część: nie potrzebujesz wielu zatwierdzeń, ponieważ origin/masterjest już na zatwierdzeniu, którego chcesz zresetować! Kredytem
caesarsol

4
To powinna być zaakceptowana odpowiedź. Prosty, oczywisty, bezpośredni, działa niezależnie od liczby zatwierdzeń i tylko przy użyciu podstawowej funkcjonalności Git. Zrobiłem te kroki z TortoiseGit. Dzięki! :)
Ian Grainger

1
Myślałem, że to najlepsza odpowiedź, ale ma pewne ograniczenia. Pomaga to tylko wtedy, gdy niedawno wyciągnąłeś zdalnie. Zakłada się, że masz pilota na początek. Jeśli masz tylko „główne” oddziały lokalne, a poprawka do nowej funkcji jest poprawna, jedyną prawidłową odpowiedzią jest twardy reset na master odliczający pewną liczbę zatwierdzeń.
pauljohn32

111

Jeśli masz czystą (niezmodyfikowaną) kopię roboczą

Aby cofnąć jeden zatwierdzenie (pamiętaj, aby zanotować skrót zatwierdzenia dla następnego kroku):

git reset --hard HEAD^

Aby pobrać to zatwierdzenie do innej gałęzi:

git checkout other-branch
git cherry-pick COMMIT-HASH

Jeśli zmodyfikowałeś lub nieśledziłeś zmiany

Należy również pamiętać, że git reset --hardbędą zabijać żadnych nieśledzone i zmodyfikowanych zmian można mieć, więc jeśli masz ci może wolisz:

git reset HEAD^
git checkout .

git rev-parse BRANCH_NAMEzdobyć sha.
wilhelmtell

12
Jeśli zapomnisz najpierw zauważyć skrót, po prostu użyj git reflog show <branch>!
Cascabel

2
@Jefromi Byłem tam przerażony przez minutę.
Ian Hunter,

13
Aby uzyskać dodatkowe poczucie bezpieczeństwa, najpierw wybierz wiśniowy wybór właściwej gałęzi, a dopiero potem zresetuj niewłaściwą gałąź.
Wiek Mooij,

1
Również w przypadku nieśledzonych zmian można git stashprzed zresetowaniem i użyć go git stash poppóźniej, aby je przywrócić, więc nie trzeba się bać --hardczęści
Clemens Klein-Robbenhaar, 12.12.2013

20

Jeśli zmiany zostały już wprowadzone, konieczne będzie wymuszenie następnego naciśnięcia po zresetowaniu HEAD.

git reset --hard HEAD^
git merge COMMIT_SHA1
git push --force

Ostrzeżenie: twardy reset spowoduje cofnięcie wszelkich niezatwierdzonych modyfikacji w kopii roboczej, natomiast wymuszenie wypchnie całkowicie stan zdalnej gałęzi aktualnym stanem gałęzi lokalnej.

Na wszelki wypadek w systemie Windows (przy użyciu wiersza polecenia systemu Windows, a nie Bash) jest to właściwie cztery ^^^^zamiast jednego, więc jest

git reset --hard HEAD^^^^

6
Należy pamiętać, że należy nie zmusi-push do oddziału, że inni ludzie są przy użyciu chyba że jest to absolutnie konieczne - w przeciwnym razie nie będą w stanie naciskać, dopóki nie zmieniają bazę. Jeśli jednak jesteś jedynym programistą używającym git, nie ma problemu.
Blair Holloway

2
Albo chyba, że ​​zdasz sobie sprawę z tego wystarczająco szybko, zanim ktokolwiek inny wyciągnie błędne błędy.
Michael Mior

Jeśli git reset --hard COMMIT_HASH git push --force
dokonałeś

17

Niedawno zrobiłem to samo, gdzie przypadkowo popełniłem zmianę na mistrza, kiedy powinienem był poświęcić się innej gałęzi. Ale niczego nie naciskałem.

Jeśli po prostu popełniłeś błąd w niewłaściwej gałęzi i od tego czasu nic nie zmieniłeś i nie wypchnąłeś repozytorium, możesz wykonać następujące czynności:

// rewind master to point to the commit just before your most recent commit.
// this takes all changes in your most recent commit, and turns them into unstaged changes. 
git reset HEAD~1 

// temporarily save your unstaged changes as a commit that's not attached to any branch using git stash
// all temporary commits created with git stash are put into a stack of temporary commits.
git stash

// create other-branch (if the other branch doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// take the temporary commit you created, and apply all of those changes to the new branch. 
//This also deletes the temporary commit from the stack of temp commits.
git stash pop

// add the changes you want with git add...

// re-commit your changes onto other-branch
git commit -m "some message..."

UWAGA: w powyższym przykładzie przewinąłem 1 zatwierdzenie z git reset HEAD ~ 1. Ale jeśli chcesz przewinąć n zatwierdzeń, możesz zresetować HEAD ~ n.

Ponadto, jeśli ostatecznie popełniłeś błąd w niewłaściwej gałęzi, a także napisałeś trochę kodu, zanim zdasz sobie sprawę, że popełniłeś błąd w niewłaściwej gałęzi, możesz użyć git stash, aby zapisać swoją pracę w toku:

// save the not-ready-to-commit work you're in the middle of
git stash 

// rewind n commits
git reset HEAD~n 

// stash the committed changes as a single temp commit onto the stack. 
git stash 

// create other-branch (if it doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// apply all the committed changes to the new branch
git stash pop

// add the changes you want with git add...

// re-commit your changes onto the new branch as a single commit.
git commit -m "some message..."

// pop the changes you were in the middle of and continue coding
git stash pop

UWAGA: Użyłem tej strony jako odnośnika https://www.clearvision-cm.com/blog/what-to-do-when-you-commit-to-the-wrong-git-branch/


Podobnie stało się ze mną, popełniłem kilka zmian w master, ale powinienem był zrobić w nowym oddziale i wysłać PR, skończyłem po prostu git checkout -b new_branchod razu, zmiany były nietknięte, po prostu wypchnąłem i utworzyłem PR, nie zrobiłem tego muszę ponownie popełnić.
Nishchal Gautam

11

Więc jeśli twoim scenariuszem jest zobowiązanie, masterale zobowiązanie się do tego another-branch(które może, ale nie musi już istnieć), ale jeszcze tego nie zrobiłeś, jest to dość łatwe do naprawienia.

// if your branch doesn't exist, then add the -b argument 
git checkout -b another-branch
git branch --force master origin/master

Teraz wszystkie twoje zobowiązania masterbędą włączone another-branch.

Pozyskane z miłości od: http://haacked.com/archive/2015/06/29/git-migrate/


wydaje się być najprostszym podejściem! Nie jestem pewien, dlaczego tak mało miłości i upwotes
keligijus

4
To chyba nie działało dla mnie. another-branchjuż istniał W tym przypadku po prostu zniweczyło zobowiązania, które podjąłem do opanowania, i ich nie założyłem another-branch.
Giselle Serate,

6

Aby rozwinąć odpowiedź, w przypadku gdy masz wiele zatwierdzeń do przejścia, np. developDo new_branch:

git checkout develop # You're probably there already
git reflog # Find LAST_GOOD, FIRST_NEW, LAST_NEW hashes
git checkout new_branch
git cherry-pick FIRST_NEW^..LAST_NEW # ^.. includes FIRST_NEW
git reflog # Confirm that your commits are safely home in their new branch!
git checkout develop
git reset --hard LAST_GOOD # develop is now back where it started

1
Miałem trzy zobowiązania do wycofania się i wydaje się, że to pytanie wyciągnęło mnie z ognia. Dzięki!
holdenweb

3

Jeśli napotkasz ten problem i masz program Visual Studio, możesz wykonać następujące czynności:

Kliknij oddział prawym przyciskiem myszy i wybierz View History:

wprowadź opis zdjęcia tutaj

Kliknij zatwierdzenie prawym przyciskiem myszy, do którego chcesz wrócić. I w razie potrzeby przywróć lub zresetuj.

wprowadź opis zdjęcia tutaj


3

Dla wielu zatwierdzeń w niewłaściwej gałęzi

Jeśli dla ciebie jest to tylko 1 zatwierdzenie, istnieje wiele innych łatwiejszych rozwiązań resetowania. Dla mnie przypadkowo wykonałem około 10 zobowiązań master, nazwijmy tobranch_xyz , i nie chciałem stracić historii .

To, co możesz zrobić, a co mnie uratowało, to użycie tej odpowiedzi jako odniesienia, przy użyciu 4-etapowego procesu, czyli:

  1. Utwórz nowy oddział tymczasowy z master
  2. Scal z gałęzią pierwotnie przeznaczoną dla zatwierdzeń, tj branch_xyz
  3. Cofnij zatwierdza na master
  4. Usuń gałąź tymczasową.

Oto szczegółowo powyższe kroki -

  1. Utwórz nowy oddział z master(gdzie przypadkowo popełniłem wiele zmian)

    git checkout -b temp_branch_xyz
    

    Uwaga: -bflaga służy do utworzenia nowego oddziału.
    Aby zweryfikować, czy udało nam się to zrobić poprawnie, postaram się szybko git branchupewnić, że jesteśmy w temp_branch_xyzoddziale, i git logsprawdzić, czy poprawnie wykonaliśmy zatwierdzenia.

  2. Scal gałąź tymczasową z gałęzią pierwotnie przeznaczoną dla zatwierdzeń, tj branch_xyz.
    Najpierw przejdź do oryginalnej gałęzi, tj. branch_xyz(Może być konieczne, git fetchjeśli nie masz)

    git checkout branch_xyz
    

    Uwaga: Nie używamy -bflagi
    Teraz połączmy gałąź tymczasową z gałęzią, którą aktualnie realizujemybranch_xyz

    git merge temp_branch_xyz
    

    Być może będziesz musiał zająć się tutaj niektórymi konfliktami, jeśli są. Możesz pchnąć (chciałbym) lub przejść do następnych kroków, po udanym scaleniu.

  3. Cofnij przypadkowe zatwierdzenia przy masterużyciu tej odpowiedzi jako odniesienia, najpierw przełącz namaster

    git checkout master
    

    następnie cofnij to do końca, aby dopasować do pilota (lub konkretnego zatwierdzenia, jeśli chcesz)

    git reset --hard origin/master
    

    Znowu zrobię to git logprzed i po, aby upewnić się, że zamierzone zmiany weszły w życie.

  4. Kasowanie dowodów, czyli usuwanie gałęzi tymczasowej. W tym celu musisz najpierw sprawdzić gałąź, w której temp został scalony, tj. branch_xyz(Jeśli pozostaniesz masteri wykonasz poniższe polecenie, możesz dostać a error: The branch 'temp_branch_xyz' is not fully merged), więc

    git checkout branch_xyz
    

    a następnie usuń dowód tego nieszczęścia

    git branch -d temp_branch_xyz
    

Proszę bardzo.


1

Jeśli gałąź, do której chcesz zastosować zmiany, już istnieje ( na przykład gałąź rozwija ), postępuj zgodnie z instrukcjami dostarczonymi przez fotanus poniżej:

git checkout develop
git rebase develop my_feature # applies changes to correct branch
git checkout develop # 'cuz rebasing will leave you on my_feature
git merge develop my_feature # will be a fast-forward
git branch -d my_feature

I oczywiście możesz użyć tempbranch lub innej nazwy oddziału zamiast my_feature jeśli chcesz.

Ponadto, jeśli ma to zastosowanie, opóźnij skasowanie popu (zastosuj), aż do momentu połączenia w oddziale docelowym.


Myślę, że pierwsze polecenie (kasa rozwijająca się) jest niepotrzebne ... rebase po prostu wypisze „moją_funkcję” jako pierwszą rzecz.
JoelFan

Możesz także pominąć parametr „my_feature” polecenia „rebase” (ponieważ już sprawdziłeś „my_feature”). możesz również pominąć parametr „rozwijania” „scalania” (ponieważ już wymeldowałeś się z „rozwijania”)
JoelFan

1

Dla mnie zostało to rozwiązane przez cofnięcie zatwierdzenia, które nacisnąłem, a następnie wybranie wiśni, które zatwierdza do drugiej gałęzi.

git checkout branch_that_had_the_commit_originally
git revert COMMIT-HASH
git checkout branch_that_was_supposed_to_have_the_commit
git cherry pick COMMIT-HASH

Możesz użyć git logdo znalezienia poprawnego skrótu i ​​możesz wprowadzać te zmiany w dowolnym momencie!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.