Jak trwale usunąć kilka zatwierdzeń ze zdalnego oddziału

489

Wiem, że przepisywanie historii jest złe, yada yada.

Ale jak trwale usunąć kilka zatwierdzeń ze zdalnego oddziału?

Arnis Lapsa
źródło
96
Tak, to naprawdę źle, yada yada, ale z jakiegoś powodu muszę to lubić.
James Morris,
44
Wiem, że to głupie, ale czasami zdarza się gówno - na przykład testowanie logowania i używanie w kodzie haseł tekstowych, które są prawdziwymi danymi uwierzytelniającymi. I
ups
6
prawdziwe dane logowania. Tak, przypomina mi się whoopos
Hello Universe
1
Możliwy duplikat zatwierdzeń usuwania z oddziału w Git
wjandrea,
2
Jestem bardzo zmęczony tą akademicką grą o tym, jak niebezpieczne jest to i jak nigdy nie należy tego robić Yada Yada. Są chwile, w których zdecydowanie lepiej jest usuwać rzeczy z historii gitów i radzić sobie z konfliktami / łamaniem innych deweloperów. To naprawdę takie proste. Ludzie, którzy to ignorują, prawdopodobnie nigdy nie pracowali poza klasą.
zmiażdżyć

Odpowiedzi:

368

Jesteś git reset --hardoddziałem lokalnym, aby usunąć zmiany z działającego drzewa i indeksu, a git push --forceTwój zmieniony oddział lokalny do pilota. ( inne rozwiązanie tutaj , obejmujące usunięcie zdalnej gałęzi i ponowne jej przekazanie)

Ta SO odpowiedź ilustruje niebezpieczeństwo takiego polecenia, szczególnie jeśli ludzie polegają na odległej historii swoich lokalnych repozytoriów.
Musisz być przygotowany, aby wskazać ludziom do wychodzenie z UPSTREAM rebase części git rebasestrony man


Z Git 2.23 (sierpień 2019, dziewięć lat później) użyjesz nowego polecenia git switch.
To znaczy: (zastąp liczbą zatwierdzeń do usunięcia)git switch -C mybranch origin/mybranch~n
n

To przywróci indeks i działające drzewo, tak jak git reset --hardzrobiłby to.

VonC
źródło
Dziwne. Czuję, że już tego próbowałem. W połączeniu z pewnymi zmianami - działa jak urok. Dzięki.
Arnis Lapsa,
7
@Arnis: idealny wtedy;) na push --forcewyjeździe
VonC
Użyłem BFG Repo-Cleaner, aby pozbyć się wrażliwych danych, które pozostawiły mnie z „nienazwanym” odgałęzieniem z oryginalnym plikiem na nim, po zresetowaniu do ostatniego poszukiwanego zatwierdzenia i twardego wypychania do źródła, wszystko poszło dobrze (:
Rodrirokr
Zauważ, że adres URL zatwierdzenia jest nadal aktywny (przynajmniej przez jakiś czas), więc jeśli ktoś ma adres URL zatwierdzenia (dałeś go bogu, wie dlaczego), będzie mógł uzyskać dostęp do kodu.
Mosh Feu
1
@MoshFeu Prawda: git gcnie zawsze jest uruchamiana wystarczająco często po stronie zdalnej. Na przykład na GitHub: twitter.com/githubhelp/status/387926738161774592?lang=es
VonC
248

Pamiętaj tylko, aby użyć last_working_commit_id, gdy cofasz niedziałający zatwierdzenie

git reset --hard <last_working_commit_id>

Nie możemy więc zresetować tego commit_id, czego nie chcemy.

W takim razie musimy przesłać do zdalnej gałęzi:

git push --force
hd84335
źródło
10
Idealna, elegancka, najprostsza odpowiedź. Właśnie wróciłem do ostatniego zatwierdzenia dźgnięcia, którego potrzebowałem zarówno zdalnie, jak i lokalnie
lauWM,
2
To spowodowało, że straciłem także lokalne zmiany. Nie spodziewałem się tego. Ale lepiej, niż podanie osobistego hasła do repozytorium pracy.
Airwavezx
3
możesz zapisać lokalne zmiany za pomocą git stash .... zrób kilka rzeczy ... i git stash pop (twoje lokalne zmiany powróciły)
MonTea
To daje mi błąd jako „zdalny: błąd: odmawianie
ref
@Airwavezx, co git reset --hardpowinno zrobić.
Łukasz
146

Ważne: Upewnij się, że określiłeś, które gałęzie na „git push -f”, w przeciwnym razie możesz przypadkowo zmodyfikować inne gałęzie! [*]

W tym samouczku pokazano trzy opcje . W przypadku zerwania linku zostawię tutaj główne kroki.

  1. Cofnij pełne zatwierdzenie
  2. Usuń ostatni zatwierdzenie
  3. Usuń zatwierdzenie z listy

1 Cofnij pełne zatwierdzenie

git revert dd61ab23

2 Usuń ostatni zatwierdzenie

git push <<remote>> +dd61ab23^:<<BRANCH_NAME_HERE>>

lub, jeśli oddział jest dostępny lokalnie

git reset HEAD^ --hard
git push <<remote>> -f

gdzie + dd61 ... jest twoim hashem zatwierdzającym, a git interpretuje x ^ jako element nadrzędny x, a + jako wymuszone nie-fastforwared push.

3 Usuń zatwierdzenie z listy

git rebase -i dd61ab23^

Otworzy się i edytor pokaże listę wszystkich zatwierdzeń. Usuń ten, którego chcesz się pozbyć. Ukończ bazę i wciśnij siłę, aby wykonać repo.

git rebase --continue
git push <remote_repo> <remote_branch> -f
reefaktor
źródło
5
Upewnij się, że określiłeś, które gałęzie na "git push <remote_repo> <remote_branch> -f", albo możesz przypadkowo zmodyfikować inne gałęzie!
Nigel Sheridan-Smith
Tylko kroki 1 i 2 wykonały zadanie i odpowiedziały na oryginalne pytanie. (Nie uruchamiaj kroku 3)
Saad Benbouzid
Są to opcje dla różnych scenariuszy, a nie kroki do podjęcia. W moim przypadku interaktywny rebase (Opcja 3) zrobił to, czego szukałem.
Steve Blackwell
Musiałem jednak zrobić krok 3. Dlaczego nie powinieneś uruchomić tego @ Saada? Na szczęście mój <<remote>> był po prostu domyślnym „początkiem”, a <remote_branch> domyślnym „mistrzem”
Bart
30

Jeśli chcesz usunąć na przykład ostatnie 3zatwierdzenia, uruchom następujące polecenie, aby usunąć zmiany z systemu plików (drzewa roboczego) i zatwierdzić historię (indeks) w lokalnym oddziale:

git reset --hard HEAD~3

Następnie uruchom następujące polecenie (na komputerze lokalnym), aby zmusić zdalny oddział do przepisania historii:

git push --force

Gratulacje! Wszystko gotowe!

Niektóre uwagi:

Możesz pobrać żądany identyfikator zatwierdzenia, uruchamiając

git log

Następnie można wymienić HEAD~Nw <desired-commit-id>ten sposób:

git reset --hard <desired-commit-id>

Jeśli chcesz zachować zmiany w systemie plików i po prostu zmodyfikować indeks (historię zatwierdzeń), użyj --softflagi jak git reset --soft HEAD~3. Następnie masz szansę sprawdzić najnowsze zmiany i zachować lub upuścić wszystkie lub ich części. W drugim przypadku runnig git statuspokazuje pliki zmienione od tego czasu <desired-commit-id>. Jeśli użyjesz --hardopcji, git statuspowie ci, że twój oddział lokalny jest dokładnie taki sam jak oddział zdalny. Jeśli nie używasz --hardani --soft, używany jest tryb domyślny --mixed. W tym trybie git help resetmówi:

Resetuje indeks, ale nie działające drzewo (tzn. Zmienione pliki są zachowane, ale nie są oznaczone do zatwierdzenia) i zgłasza, co nie zostało zaktualizowane.

Abdollah
źródło
10

To może być za mało za późno, ale pomogła mi fajnie brzmiąca opcja „nuklearna”. Zasadniczo za pomocą polecenia filter-branchmożesz usunąć pliki lub zmienić coś w dużej liczbie plików w całej historii git.

Najlepiej to wyjaśniono tutaj .

jansmolders86
źródło
9
Nie jest za późno. Może się przydać wędrowcom z podobnymi problemami :)
Arnis Lapsa
9

Uproszczenie z odpowiedzi pctroll, podobnie na podstawie tego postu na blogu .

# look up the commit id in git log or on github, e.g. 42480f3, then do
git checkout master
git checkout your_branch
git revert 42480f3
# a text editor will open, close it with ctrl+x (editor dependent)
git push origin your_branch
# or replace origin with your remote
ted.strauss
źródło
2
Działa dla mnie, dzięki. I chcę trwale usunąć jedno zatwierdzenie (np. Zawiera pwd) ze zdalnej historii oddziału, jak to zrobić?
Uśmiecha się
1
Działa również dla mnie, ale mam takie samo pytanie jak Smiles, nie chcę, aby ktokolwiek widział moje zatwierdzenie / pogłos w historii ... jak to usunąć?
Roberto Rodriguez
4

Czasami najłatwiejszym sposobem rozwiązania tego problemu jest utworzenie nowej gałęzi z miejsca, w którym wiesz, że kod jest dobry. Następnie możesz zostawić błędną historię oddziału w spokoju, na wypadek, gdybyś musiał później wybrać inne zatwierdzenia. Zapewnia to również, że nie straciłeś historii zatwierdzeń.

Z lokalnego oddziału, który popełnił błąd:

git log

skopiuj skrót zatwierdzenia, w którym chcesz, aby gałąź była w, i zamknij dziennik git

git checkout theHashYouJustCopied
git checkout -b your_new_awesome_branch

Teraz masz nowy oddział tak, jak chcesz.

Jeśli potrzebujesz również zachować konkretne zatwierdzenie z błędnego oddziału, którego nie ma w nowym oddziale, możesz po prostu wybrać konkretny zatwierdzenie, którego potrzebujesz:

git checkout the_errant_branch
git log

Skopiuj skrót zatwierdzenia jednego zatwierdzenia, którego potrzebujesz, aby pobrać do dobrej gałęzi i zamknąć dziennik git.

git checkout your_new_awesome_branch
git cherry-pick theHashYouJustCopied

Poklep się po plecach.

Douglas.Sesar
źródło
bardzo łatwe i kogo to obchodzi, jeśli masz martwą gałąź? zrób nowy oddział i gotowe!
Andrew Fox
To naprawdę doskonała odpowiedź. Cieszę się, że to zrobiłem zamiast wybierania wiśni lub manipulowania zdalną gałęzią.
Magnilex
0
 git reset --soft commit_id
 git stash save "message"
 git reset --hard commit_id
 git stash apply stash stash@{0}
 git push --force
pandorago
źródło