Mam repozytorium git, które wygląda następująco:
A -> B -> C -> D -> HEAD
Chcę, aby głowa oddziału wskazywała na A, tzn. Chcę, aby B, C, D i HEAD zniknęły i chcę, aby głowa była synonimem A.
Wygląda na to, że mogę albo spróbować dokonać zmiany bazy (nie dotyczy, ponieważ wprowadziłem zmiany pomiędzy), albo cofnąć. Ale jak cofnąć wiele zatwierdzeń? Czy cofam pojedynczo? Czy kolejność jest ważna?
git
commit
git-revert
Rachunek
źródło
źródło
git push -f HEAD~4:master
(zakładając, że zdalna gałąź jest masterem). Tak, możesz wcisnąć dowolne takie zatwierdzenie.git revert
.Odpowiedzi:
Rozszerzanie tego, co napisałem w komentarzu
Ogólna zasada mówi, że nie powinieneś przepisywać (zmieniać) historii, którą opublikowałeś, ponieważ ktoś mógł na tym oprzeć swoją pracę. Jeśli przepiszesz (zmienisz) historię, będziesz miał problemy z scaleniem ich zmian i aktualizacją.
Dlatego rozwiązaniem jest utworzenie nowego zatwierdzenia, które przywróci zmiany , których chcesz się pozbyć. Możesz to zrobić za pomocą polecenia git revert .
Masz następującą sytuację:
(strzałki tutaj odnoszą się do kierunku wskaźnika: odniesienie „nadrzędne” w przypadku zatwierdzeń, górne zatwierdzenie w przypadku główki gałęzi (odniesienie do gałęzi) i nazwa gałęzi w przypadku odniesienia HEAD).
Co musisz stworzyć, to:
gdzie „[(BCD) ^ - 1]” oznacza zatwierdzenie, które odwraca zmiany w zatwierdzeniach B, C, D. Matematyka mówi nam, że (BCD) ^ - 1 = D ^ -1 C ^ -1 B ^ -1, więc wymaganą sytuację można uzyskać za pomocą następujących poleceń:
Alternatywnym rozwiązaniem byłoby pobranie zawartości zatwierdzenia A i zatwierdzenie tego stanu:
Wtedy miałbyś następującą sytuację:
Zatwierdzenie A 'ma taką samą treść jak zatwierdzenie A, ale jest innym zatwierdzeniem (komunikat zatwierdzenia, rodzice, data zatwierdzenia).
Rozwiązanie Jeff Ferland, zmodyfikowany przez Charles Bailey opiera się na tej samej idei, ale korzysta git resetu :
źródło
git checkout -f A -- .
one usunięte, będziesz musiał to zrobić ręcznie. Zastosowałem tę strategię teraz, dzięki Jakubowigit checkout foo
może oznaczać gałąź kasyfoo
(przejście do gałęzi) lub plik kasy foo (z indeksu).--
służy do jednoznaczności, np.git checkout -- foo
zawsze dotyczy pliku.git revert --no-commit D C B
git revert
nie akceptowałem wielu zatwierdzeń; to całkiem nowy dodatek.Czysty sposób, który uważam za użyteczny
To polecenie przywraca ostatnie 3 zatwierdzenia tylko jednym zatwierdzeniem.
Nie przepisuje też historii.
źródło
git commit
stamtąd faktycznie wykona zatwierdzenie.HEAD~3..
jest taki sam jakHEAD~3..HEAD
W tym celu wystarczy użyć polecenia revert , określając zakres zatwierdzeń, które chcesz przywrócić.
Biorąc pod uwagę twój przykład, musisz to zrobić (zakładając, że jesteś w gałęzi „master”):
Spowoduje to utworzenie nowego zatwierdzenia w Twoim lokalnym z odwrotnym zatwierdzeniem B, C i D (co oznacza, że cofnie zmiany wprowadzone przez te zatwierdzenia):
źródło
git revert --no-commit HEAD~2..
jest nieco bardziej idiomatycznym sposobem na zrobienie tego. Jeśli jesteś w gałęzi master, nie musisz ponownie określać master. Ta--no-commit
opcja pozwala git spróbować cofnąć wszystkie zatwierdzenia naraz, zamiast zaśmiecać historię wielomarevert commit ...
wiadomościami (zakładając, że tego właśnie chcesz).master~3
.--no-commit
(więc dostajesz osobne zatwierdzenie dla każdego przywrócenia), a następnie zmiażdżyłeś je wszystkie razem w interaktywnej bazie. Połączony komunikat zatwierdzenia będzie zawierał wszystkie SHA i możesz je ustawić w dowolny sposób, używając ulubionego edytora komunikatów zatwierdzania.Podobnie jak odpowiedź Jakuba, pozwala to łatwo wybrać kolejne zatwierdzenia do cofnięcia.
źródło
B^..HEAD
, w przeciwnym razie B jest wykluczone.git revert --no-commit B^..HEAD
lubgit revert --no-commit A..HEAD
To zadziała dla wszystkich jednocześnie. Daj dobry komunikat o zatwierdzeniu.
źródło
HEAD
wyglądać,A
to prawdopodobnie chce, aby indeks się zgadzał, więcgit reset --soft D
jest to prawdopodobnie bardziej odpowiednie.git checkout A
Następniegit commit
powyżej nie działa dla mnie, ale ta odpowiedź nie.git reset --mixed D
wymagane? W szczególności dlaczegoreset
? Czy dlatego, że bez resetowania do D, HEAD wskazywałby na A, powodując, że B, C i D były „wiszące” i zbierane w śmieciach - czego nie chce? Ale dlaczego--mixed
? Już odpowiedziałeś: „--soft
zresetowanie nie przenosi indeksu ...” Zatem przenoszenie indeksu oznacza, że indeks będzie zawierał zmiany D, podczas gdy katalog roboczy będzie zawierał zmiany A - w ten sposób agit status
lubgit diff
(który porównuje Indeks [D] z Katalog roboczy [A]) pokaże substancję; ten użytkownik wraca z D do A?Najpierw upewnij się, że twoja kopia robocza nie jest modyfikowana. Następnie:
a następnie po prostu popełnij. Nie zapomnij udokumentować przyczyny wycofania.
źródło
error: cannot apply binary patch to 'some/image.png' without full index line error: some/image.png: patch does not apply
git diff --binary HEAD commit_sha_you_want_to_revert_to | git apply
git revert A..Z
dostanieszerror: commit X is a merge but no -m option was given.
Jestem tak sfrustrowany, że na to pytanie nie można po prostu odpowiedzieć. Każde inne pytanie dotyczy tego, jak prawidłowo przywrócić i zachować historię. To pytanie brzmi: „Chcę, aby szef oddziału wskazywał na A, tzn. Chcę, aby B, C, D i HEAD zniknęły, i chcę, aby głowa była synonimem A.”
Nauczyłem się dużo czytając post Jakuba, ale jakiś facet w firmie (z dostępem do wypychania do naszego oddziału „testującego” bez Pull-Request) naciskał jak 5 złych popełnień próbując naprawić i naprawić błąd, który popełnił 5 lat temu. Nie tylko to, ale jedno lub dwa żądania ściągnięcia zostały zaakceptowane, które były teraz złe. Więc zapomnij o tym, znalazłem ostatnie dobre zatwierdzenie (abc1234) i po prostu uruchomiłem podstawowy skrypt:
Powiedziałem pozostałym 5 facetom pracującym w tym repozytorium, że lepiej zanotują swoje zmiany w ciągu ostatnich kilku godzin i Wipe / Re-Branch z ostatnich testów. Koniec historii.
źródło
git push --force-with-lease
zapisanie historii tylko wtedy, gdy nikt inny nie zaangażował się w oddział po ani w zakresie zatwierdzeń do vapourize. Jeśli inni ludzie korzystali z gałęzi, jego historia nigdy nie powinna być przepisywana, a zatwierdzenie powinno być po prostu widoczne.Jest to rozwinięcie jednego z rozwiązań zawartych w odpowiedzi Jakuba
Miałem do czynienia z sytuacją, w której zmiany, które musiałem wycofać, były nieco skomplikowane, przy czym kilka z nich to scalanie zmian i musiałem unikać przepisywania historii. Nie byłem w stanie użyć serii
git revert
poleceń, ponieważ w końcu wpadłem na konflikty między dodawanymi zmianami wersji. Skończyło się na następujących krokach.Najpierw sprawdź zawartość zatwierdzenia celu, pozostawiając HEAD na końcu gałęzi:
(- upewnia się, że
<target-commit>
jest interpretowane raczej jako zatwierdzenie niż plik;. Odnosi się do bieżącego katalogu.)Następnie określ, które pliki zostały dodane do wycofanych zatwierdzeń, a zatem należy je usunąć:
Dodane pliki powinny pokazywać „A” na początku wiersza i nie powinny występować inne różnice. Teraz, jeśli jakieś pliki wymagają usunięcia, przygotuj te pliki do usunięcia:
Na koniec dokonaj zmiany wersji:
W razie potrzeby upewnij się, że wróciliśmy do pożądanego stanu:
Nie powinno być różnic.
źródło
git
HEAD tylko wierzchołkiem gałęzi?Prostym sposobem na przywrócenie grupy zatwierdzeń w repozytorium współdzielonym (używanym przez ludzi i chcącym zachować historię) jest użycie
git revert
w połączeniu z gitrev-list
. Ten ostatni dostarczy ci listę zmian, pierwszy dokona samego wycofania.Można to zrobić na dwa sposoby. Jeśli chcesz przywrócić wiele zatwierdzeń w jednym zatwierdzeniu, użyj:
spowoduje to cofnięcie potrzebnej grupy zatwierdzeń, ale pozostaw wszystkie zmiany w działającym drzewie, powinieneś je wszystkie zatwierdzić jak zwykle.
Inną opcją jest posiadanie jednego zatwierdzenia na cofniętą zmianę:
Na przykład, jeśli masz drzewo zatwierdzania, takie jak
aby przywrócić zmiany z eee na bbb , uruchom
źródło
Żadne z nich nie działało dla mnie, więc miałem trzy zatwierdzenia do wycofania (ostatnie trzy zatwierdzenia), więc zrobiłem:
Działa jak urok :)
źródło
Moim zdaniem bardzo łatwym i czystym sposobem może być:
wróć do A.
skieruj głowę mistrza na bieżący stan
zapisać
źródło
git checkout master; git reset --hard A
? A jeśli nie, czy mógłbyś wyjaśnić nieco więcej na temat tego, co to robi?Jeśli chcesz tymczasowo cofnąć zatwierdzenia funkcji, możesz użyć serii następujących poleceń.
Oto jak to działa
git log --pretty = oneline | grep „nazwa_funkcji” | cut -d '' -f1 | xargs -n1 git revert --no-edit
źródło