Git: usunięcie commitów z historii

Chciałbym zrobić następującą rzecz: muszę usunąć z historii commity pojedynczych plików. W zasadzie zależy mi na przywróceniu pierwotnej treści jakiegoś pliku, ale tak, by po wszystkich modyfikacjach tego pliku nie pozostał żaden ślad w historii. Jak można to najsprytniej zrobić?

git rebase -i ...

W … wstawiasz hash commita od ktorego zaczynasz rebase i usuwasz odpowiednie linijki. O cos takiego chodzi?

http://www.gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html

btw. Trzeba z tym uwazac. :wink:

Alternatywne rozwiązanie: http://help.github.com/removing-sensitive-data/

Jak się domyślam ktoś wstawił do repo jakieś poufne dane. Nie pozostaje nic innego jak git filter-branch. Pamiętaj że po tej operacji cała historia zostanie przepisana (nowe sha1 commitów) więc każdy kto posiada kopię repo musi albo na nowo je sklonować albo odpowiednio pocheckoutować każdy zdalny branch (po fetchu) a na lokalnych branchach zrobić rebase.

Samym rebasem nie polecam bo możesz coś przeoczyć, a poza tym będzie to upierdliwe edytować każdy commit.

Zakładając że wiesz co robisz, zrozumiałeś że zmienisz sobie SHA1 commitów i przepiszesz historię jest jeszcze jedna rzecz.

Trzeba pamiętać że po filter-branch czy po rebase te poufne dane które chcieliśmy usunąć nadal mogą zostać na serwerze, jako luźne obiekty gita. Po całym sprzątaniu warto zrobić jeszcze

git gc --prune --aggressive

Po wszystkim

git push --force

I powinno być czysto.

oraz na koniec zrobić git push

A ja bym tam zmienił hasła na inne niż te co zostały do git’a dodane i po problemie.

+1 :wink:

+1

+1

+1

+1

Ale problemem mógł być np. dodany jakiś spory plik binarny :stuck_out_tongue:

-1

Brzmi prosto ale w praktyce jest dużo bardziej upierdliwe i błędogenne niż filter-branch. Po pierwsze można to naiwnie zinterpretować jako “usuń hasło z pliku zacommituj” co jak się domyślam nie miałeś na myśli (zostaje historia). Jeśli chciałbyś w ten sposób usunąć z historii to musiałbyś fizycznie zmodyfikować wszystkie commity, które dodają jakieś sensytywne dane (np. do pliku config/database.yml) czyli w praktyce zrobić ogromny rebase. Ale to znów jest prostsze niż wygląda. Musiałbyś zrobić to na każdym branchu oraz musiałbyś usunąć wszystkie tagi z repozytorium. Czyli to co zaproponowałeś to takie symulowanie git filter-branch :).

raczej chodziło o zmianę hasła np do bazy na inne niż poleciało do repo, no ale może tylko ja tak zrozumiałem?

Ja zrozumiałem tak samo jak Gotar i wszyscy pozostali dający +1. Oj, Radarek :stuck_out_tongue:

Przecież tiwi jasno napisał, że chce usunąć commity z historii. Teraz to już nie wiem czy się zbijacie czy serio piszecie :).

Ja miałem na myśli to samo co prawie wszyscy pomyśleli ale jeśli faktycznie problemem jest dodanie sporego pliku binarnego to inna sprawa zupełnie niż przypadkiem dodane hasło i rady odnoszące się do meritum tematu były bardziej trafne :slight_smile:

Huh, ale wątek się rozwinął :stuck_out_tongue: Dzięki wszystkim za odpowiedzi. Dla jasności: od początku istnienia projektu był w nim plik X. W pewnym momencie ktoś do niego zacommitował poufne informacje (nie tylko hasła). Do dnia dzisiejszego to była jedyna zmiana w tym pliku. Ja teraz chciałbym przywrócić wersję oryginalną tak, aby wyczyścić z historii informacje o tym nieszczęsnym commicie. Co do konsekwencji, to zdaję sobie sprawę, repo jest na razie u mnie lokalnie, a projekt migrowałem z svna, więc zanim cokolwiek z nim dalej zrobię, wolałbym wyczyścić jednak problematyczne dane. Usunięcie pliku z całej historii jest proste i to robiłem. Pytanie dotyczyło usunięcia części historii pliku. :slight_smile:

Ostatecznie wymyśliłem coś takiego:

git filter-branch --index-filter 'git co 6720a55 nazwa_pliku' -f -- --all 6720a55..HEAD

Działa, ‘git log nazwa_pliku’ pokazuje tylko jednego commita, diff z kopią sprzed zmiany pokazał różnice tylko w tym pliku, więc nic innego się nie zepsuło :wink: