Jak przywrócić wiele commitów git?

Mam repozytorium git, które wygląda tak:

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 head był synonimem A.

Wygląda na to, że mogę albo spróbować rebase (Nie dotyczy, ponieważ pchnąłem zmiany pomiędzy), albo przywrócić. Ale jak mogę przywrócić wiele commitów? Czy odwracam po kolei? Czy zamówienie jest ważne?

Author: prosoitos, 2009-09-23

15 answers

rozszerzenie tego co napisałem w komentarzu

Ogólna zasada jest taka, że nie należy przepisywać (zmieniać) opublikowanej historii, ponieważ ktoś mógł na niej oprzeć swoją pracę. Jeśli zmienisz (zmienisz) historię, będziesz miał problemy z połączeniem ich zmian i ich aktualizacją.

Więc rozwiązaniem jest utworzenie nowego commita, który odwraca zmiany, których chcesz się pozbyć. Możesz to zrobić używając git revert dowództwo.

Masz następującą sytuację:

A <-- B  <-- C <-- D                                  <-- master <-- HEAD

(strzałki odnoszą się do kierunku wskaźnika: odniesienie "rodzica" w przypadku commitów, górne zatwierdzenie w przypadku gałęzi head (branch ref) oraz nazwa gałęzi w przypadku gałęzi reference).

To, co musisz utworzyć, to:

A <-- B  <-- C <-- D <-- [(BCD)-1]                   <-- master <-- HEAD

Gdzie [(BCD)^-1] oznacza commit, który odwraca zmiany w commitach B, C, D. Matematyka mówi nam, że (BCD)-1 = D-1 C-1 B-1, można więc uzyskać wymaganą sytuację za pomocą następujących poleceń:

$ git revert --no-commit D
$ git revert --no-commit C
$ git revert --no-commit B
$ git commit -m "the commit message for all of them"

Działa dla wszystkiego oprócz scalania commitów.


Alternatywnym rozwiązaniem byłoby zamówienie Zawartość commit A i commit ten stan. Działa również z merge commit. Dodane pliki nie zostaną jednak usunięte. Jeśli masz jakieś lokalne zmiany git stash to najpierw:

$ git checkout -f A -- . # checkout that revision over the top of local files
$ git commit -a

Wtedy masz następującą sytuację:

A <-- B  <-- C <-- D <-- A'                       <-- master <-- HEAD

The commit A ' ma taką samą zawartość jak commit A, ale jest innym commitem (komunikat commit, rodzice, Data commit).


Alternate solution by Jeff Ferland, modified by Charles Bailey opiera się na tym samym pomyśle, ale używa git reset. Tutaj jest nieco zmodyfikowany, ten sposób działa na wszystko:

$ git reset --hard A
$ git reset --soft D # (or ORIG_HEAD or @{1} [previous location of HEAD]), all of which are D
$ git commit
 1517
Author: Jakub Narębski,
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-10-12 17:20:57

Clean way which I found useful

git revert --no-commit HEAD~3..

To polecenie odwraca Ostatnie 3 commity tylko jednym commitem.

Również nie przepisuje historii.

.. pomaga utworzyć zakres. Znaczenie HEAD~3.. jest takie samo jak HEAD~3..HEAD

 359
Author: deepdive,
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-09-24 12:27:32

Aby to zrobić, musisz użyć revert, określając zakres zmian, które chcesz przywrócić.

Biorąc pod uwagę Twój przykład, musisz to zrobić (zakładając, że jesteś na gałęzi 'master'):

git revert master~3..master

Lub git revert B...D lub git revert D C B

Utworzy to nowy commit w Twoim lokalnym z odwrotnym commitem B, C i D (co oznacza, że cofnie zmiany wprowadzone przez te commity):

A <- B <- C <- D <- BCD' <- HEAD
 252
Author: Victor,
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-10-12 17:13:42

Podobnie jak odpowiedź Jakuba, pozwala to łatwo wybrać kolejne commity do odwrócenia.

# revert all commits from B to HEAD, inclusively
$ git revert --no-commit B..HEAD  
$ git commit -m 'message'
 74
Author: konyak,
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
2014-07-31 18:49:15
git reset --hard a
git reset --mixed d
git commit

To będzie działać jako odwrócenie dla wszystkich naraz. Przekaż dobrą wiadomość.

 71
Author: Jeff Ferland,
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
2009-09-23 00:45:31

Najpierw upewnij się, że kopia robocza nie jest modyfikowana. Wtedy:

git diff --binary HEAD commit_sha_you_want_to_revert_to | git apply

A potem po prostu commit. Nie zapomnij udokumentować, co jest powodem przywrócenia.

 53
Author: mateusz.fiolka,
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-10-12 17:17:02

Jestem tak sfrustrowana, ż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 mówi "chcę, aby szef Oddziału wskazywał na A, tzn. chcę B, C, D, A głowa do zniknąć i chcę, aby głowa była synonimem A."

git checkout <branch_name>
git reset --hard <commit Hash for A>
git push -f

Wiele się nauczyłem czytając post Jakuba, ale jakiś facet w firmie (z dostępem do push do naszej" testowej " gałęzi bez Pull-Requestu) pchnął jak 5 źle popełnia błąd, który popełnił 5 commitów temu. Nie tylko to, ale przyjęto jedno lub dwa żądania ściągnięcia, które teraz były złe. Więc zapomnij o tym, znalazłem ostatni dobry commit (abc1234) i po prostu uruchomiłem podstawowy skrypt:

git checkout testing
git reset --hard abc1234
git push -f

Powiedziałem pozostałym 5 facetom pracującym w tym repo, że lepiej zanotują zmiany za ostatnie kilka godzin i wyczyszczą / przełączą z najnowszych testów. Koniec historii.

 45
Author: Suamere,
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
2016-07-11 23:29:24

jest to rozszerzenie jednego z rozwiązań podanych w odpowiedzi Jakuba

Miałem do czynienia z sytuacją, w której commity, które musiałem cofnąć, były nieco złożone, z kilkoma commitami, które były commitami scalającymi i musiałem unikać przepisywania historii. Nie byłem w stanie użyć serii git revert poleceń, ponieważ w końcu natrafiłem na konflikty między dodawanymi zmianami rewersji. Skończyło się na następujących krokach.

Najpierw sprawdź zawartość w tym celu należy wykonać następujące czynności:]}

$ git checkout -f <target-commit> -- .

(the -- upewnia się, że <target-commit> jest interpretowany jako commit, a nie Plik; the . odnosi się do bieżącego katalogu.)

Następnie określ, które pliki zostały dodane w commitach, które są wycofywane, a zatem muszą zostać usunięte:

$ git diff --name-status --cached <target-commit>

Dodane pliki powinny pojawiać się z" A " na początku wiersza i nie powinno być innych różnic. Teraz, jeśli jakieś pliki muszą zostać usunięte, stage te pliki do usunięcia:

$ git rm <filespec>[ <filespec> ...]

Na koniec Zatwierdź rewersję:

$ git commit -m 'revert to <target-commit>'

W razie potrzeby upewnij się, że wracamy do pożądanego stanu:

$git diff <target-commit> <current-commit>

Nie powinno być różnic.

 14
Author: Warren Dew,
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-06-07 15:28:19

Łatwym sposobem na przywrócenie grupy commitów w repozytorium współdzielonym (których używają ludzie i chcesz zachować historię) jest użycie git revert w połączeniu z git rev-list. Ten ostatni dostarczy Ci listę commitów, ten pierwszy sam zrobi rewert.

Są na to dwa sposoby. Jeśli chcesz przywrócić wiele commitów w jednym commicie użyj:
for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert --no-commit $i; done

Spowoduje to odwrócenie grupy commitów, których potrzebujesz, ale pozostaw wszystkie zmiany w roboczym drzewie, powinieneś zatwierdzić Wszystkie jak zwykle później.

Inną opcją jest posiadanie jednego commita za cofniętą zmianę:

for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert --no-edit -s $i; done

Na przykład, jeśli masz drzewo commit jak

 o---o---o---o---o---o--->    
fff eee ddd ccc bbb aaa

Aby przywrócić zmiany z eee do bbb, Uruchom

for i in `git rev-list eee^..bbb`; do git revert --no-edit -s $i; done
 7
Author: Ruslan Kabalin,
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-10-12 14:13:43

Żaden z nich nie działał dla mnie, więc miałem trzy commity do przywrócenia (ostatnie trzy commity), więc zrobiłem:

git revert HEAD
git revert HEAD~2
git revert HEAD~4
git rebase -i HEAD~3 # pick, squash, squash

Zadziałało jak czar :)

 5
Author: Dorian,
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-01-24 00:28:34

Moim zdaniem bardzo łatwym i czystym sposobem może być:

Wróć do A

git checkout -f A

Wskaż głowę mistrza do aktualnego stanu

git symbolic-ref HEAD refs/heads/master

Zapisz

git commit
 2
Author: nulll,
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-11-28 12:06:24

Naprawdę chciałem uniknąć twardych resetów, oto co wymyśliłem.

A -> B -> C -> D -> HEAD

Aby wrócić do A (czyli 4 kroki wstecz):

git pull                  # Get latest changes
git reset --soft HEAD~4   # Set back 4 steps
git stash                 # Stash the reset
git pull                  # Go back to head
git stash pop             # Pop the reset 
git commit -m "Revert"    # Commit the changes
 1
Author: Nebulastic,
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-30 10:17:09

Jeśli

  1. mają połączony commit i
  2. nie jesteś w stanie przywrócić, a
  3. nie masz nic przeciwko zgniataniu historii, którą masz cofnąć,

Wtedy możesz

git reset --soft HEAD~(number of commits you'd like to revert)
git commit -m "The stuff you didn't like."
git log
# copy the hash of your last commit
git revert <hash of your last (squashed) commit>

Następnie, gdy chcesz przesunąć zmiany pamiętaj, aby użyć znacznika -f, ponieważ zmodyfikowałeś historię

git push <your fork> <your branch> -f
 0
Author: ScottyBlades,
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
2021-01-16 05:56:29

Prawdopodobnie mniej eleganckie niż inne podejścia tutaj, ale zawsze używałem get reset --hard HEAD~N do cofania wielu commitów, gdzie N jest liczbą commitów, które chcesz cofnąć.

Lub, jeśli nie jesteś pewien dokładnej liczby commitów, po prostu uruchom git reset --hard HEAD^ (Co cofnie się o jeden commit) wiele razy, aż osiągniesz żądany stan.

 0
Author: Ian,
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
2021-01-20 18:02:38

Jeśli chcesz tymczasowo przywrócić commity danej funkcji, możesz użyć serii następujących poleceń.

Oto Jak to działa

Git log --pretty=oneline / grep 'feature_name' / cut - d '' - f1 / xargs-N1 git revert --no-edit

 -7
Author: Ajit Singh,
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
2016-02-11 18:47:34