Git pull po wymuszonej aktualizacji

332

Właśnie zmiażdżyłem niektóre zobowiązania git rebasei zrobiłem git push --force(co jest złe, wiem).

Teraz inni inżynierowie oprogramowania mają inną historię, a kiedy to zrobią git pull, Git się połączy. Czy istnieje sposób, aby to naprawić, z wyjątkiem robienia rm my-repo; git clone [email protected]:my-repo.git?

Potrzebuję czegoś przeciwnego git push --force, ale git pull --forcenie dał zamierzonych rezultatów.

iblue
źródło
16
mogą usunąć swój oddział i ponownie go utworzyć, bez konieczności usuwania całego repozytorium:git checkout master && git branch -D test && git checkout -b test origin/test
Florian Klein

Odpowiedzi:

509

Aby otrzymać nowe zobowiązania

git fetch

Resetowanie

Możesz zresetować zatwierdzenie dla lokalnego oddziału za pomocą git reset.

Aby zmienić zatwierdzenie oddziału lokalnego:

git reset origin/master --hard

Bądź jednak ostrożny, jak to dokumentuje:

Resetuje indeks i działające drzewo. Wszelkie zmiany w śledzonych plikach w działającym drzewie od czasu <commit> są odrzucane.

Jeśli chcesz zachować wszystkie zmiany, które wprowadziłeś lokalnie - --softzamiast tego wykonaj reset. Który zaktualizuje historię zatwierdzeń dla gałęzi, ale nie zmieni żadnych plików w katalogu roboczym (a następnie możesz je zatwierdzić).

Rebase

Możesz odtworzyć swoje lokalne zatwierdzenia na dowolnym innym zatwierdzeniu / oddziale, używając git rebase:

git rebase -i origin/master

Spowoduje to wywołanie rebase w trybie interaktywnym, w którym możesz wybrać sposób zastosowania każdego indywidualnego zatwierdzenia, którego nie ma w historii, której aktualizujesz.

Jeśli zatwierdzenia, które usunąłeś (za pomocą git push -f), zostały już wprowadzone do historii lokalnej, zostaną wymienione na liście jako zatwierdzenia, które zostaną ponownie zastosowane - będą musiały zostać usunięte w ramach bazy lub po prostu zostaną ponownie włączone do historii dla oddziału - i pojawi się w odległej historii przy kolejnym wypychaniu.

Skorzystaj z pomocy, git command --helpaby uzyskać więcej informacji i przykładów na temat dowolnego z powyższych (lub innych) poleceń.

AD7six
źródło
2
@iblue wybiera między utratą wszystkich zmian, usunięciem historii zatwierdzeń, ale zachowaniem zmian w plikach, lub próbą zastosowania każdego zatwierdzenia nad nową nagłówkiem. Najprostszą opcją jest prawdopodobnie miękki reset.
AD7six
1
@iblue Kiedy twój kolega użyje polecenia `git reabse origin / master 'i znaczy, że wcześniej mieli już pewne zatwierdzenie, git zapisze twoje zatwierdzenie z tyłu ich zatwierdzenia.
Tim
6
Warto wspomnieć, że jeśli dotyczy to innej gałęzi:git reset origin/otherbranch --hard
bmaupin
Tak więc, w celu wyjaśnienia, jest to albo : Opcja 1: reset --hard, lub Opcja 2: reset --soft+ rebase, prawda?
PlasmaBinturong
2
@PlasmaBinturong No. git reset --soft origin/masterzmieni historię zatwierdzania, aby dopasować zdalne i różnice etapów do zdalnego, które następnie zostaną zatwierdzone . W tym scenariuszu nie byłoby potrzeby dokonywania zmian w bazie (i byłoby to niemożliwe z powodu niezatwierdzonych zmian), ponieważ nie ma różnicy w historii zatwierdzeń. Dwie opcje są resetowane lub rebase - nie kombinacja obu. Proszę zadać pytanie, czy twój scenariusz jest inny niż ten, na który tu odpowiedziałem.
AD7six
16

Nie naprawi to gałęzi, które już zawierają kod, którego nie chcesz (zobacz poniżej, jak to zrobić), ale jeśli wyciągnęły jakąś gałąź i teraz chcą, aby była czysta (a nie „wyprzedzająca” przed origin / some-branch), a następnie:

git checkout some-branch   # where some-branch can be replaced by any other branch
git branch base-branch -D  # where base-branch is the one with the squashed commits
git checkout -b base-branch origin/base-branch  # recreating branch with correct commits

Uwaga: Możesz połączyć je wszystkie, umieszczając && między nimi

Uwaga 2: Florian wspomniał o tym w komentarzu, ale kto czyta komentarze, gdy szuka odpowiedzi?

Uwaga 3: Jeśli masz zanieczyszczone gałęzie, możesz utworzyć nowe na podstawie nowej „głupiej gałęzi” i po prostu zatwierdzić wybór.

Dawny:

git checkout feature-old  # some branch with the extra commits
git log                   # gives commits (write down the id of the ones you want)
git checkout base-branch  # after you have already cleaned your local copy of it as above
git checkout -b feature-new # make a new branch for your feature
git cherry-pick asdfasd   # where asdfasd is one of the commit ids you want
# repeat previous step for each commit id
git branch feature-old -D # delete the old branch

Teraz nowa funkcja jest twoją gałęzią bez dodatkowych (prawdopodobnie złych) zmian!

Tom Prats
źródło
Tego naprawdę chciałem. Ktoś zmienił gałąź główną (na bóg wie, z jakiego powodu), ale nie miałem żadnych lokalnych zmian, które chciałbym zatwierdzić lub coś w tym rodzaju. Więc wszystko, co musiałem zrobić, to usunąć moją lokalną gałąź master (co wydawało się naprawdę dziwne) i zrobić ponownie kasę. Dzięki!
Danilo Carvalho
@ Peter-Mortensen Zmiany powinny być znaczące zgodnie z stackoverflow.com/help/editing
Tom Prats
dla ostatniego kroku możesz także użyć git checkout -b base-branch origin/base-branchzgit checkout --track origin/base-branch
bluesmonk
1

Pociągnij za pomocą podstawy

Regularne pobieranie to fetch + merge, ale to, czego chcesz, to fetch + rebase. Jest to opcja z pullpoleceniem:

git pull --rebase
herman
źródło
Używam tego przez cały czas, aby pobrać najnowszy kod z mastera do mojej gałęzi funkcji, bez tych wszystkich zatwierdzeń scalania w historii.
herman