To, co chcesz zrobić, jest bardzo destrukcyjne, jeśli opublikujesz historię innym programistom. Zobacz „Odzyskiwanie z wcześniejszego uruchomienia” w git rebasedokumentacji, aby dowiedzieć się, jakie kroki należy wykonać po naprawieniu historii.
Masz co najmniej dwie opcje: git filter-branchi interaktywną bazę, obie wyjaśnione poniżej.
Za pomocą git filter-branch
Miałem podobny problem z dużymi danymi binarnymi z importu Subversion i pisałem o usuwaniu danych z repozytorium git .
Powiedz, że twoja historia gitów to:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Pamiętaj, że git lolajest to niestandardowy, ale bardzo użyteczny alias. Za pomocą --name-statusprzełącznika możemy zobaczyć modyfikacje drzewa związane z każdym zatwierdzeniem.
W zatwierdzeniu „Nieostrożny” (którego nazwa obiektu SHA1 to ce36c98) plik oops.isoto zgrywanie DVD dodane przypadkowo i usunięte w następnym zatwierdzeniu, cb14efd. Korzystając z techniki opisanej we wspomnianym blogu, polecenie do wykonania to:
git filter-branch --prune-empty -d /dev/shm/scratch \
--index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
--tag-name-filter cat -- --all
Opcje:
--prune-emptyusuwa zatwierdzenia, które stają się puste ( tj. nie zmieniają drzewa) w wyniku operacji filtrowania. W typowym przypadku ta opcja zapewnia czystszą historię.
-dnazywa tymczasowy katalog, który jeszcze nie istnieje, aby użyć go do zbudowania przefiltrowanej historii. Jeśli korzystasz z nowoczesnej dystrybucji Linuksa, określenie drzewa /dev/shmspowoduje szybsze wykonanie .
--index-filterjest głównym wydarzeniem i działa na podstawie indeksu na każdym etapie historii. Chcesz usunąć, oops.isogdziekolwiek się znajdzie, ale nie jest obecny we wszystkich zatwierdzeniach. Polecenie git rm --cached -f --ignore-unmatch oops.isousuwa zgrywanie DVD, gdy jest obecne, i w przeciwnym razie nie zawiedzie.
--tag-name-filteropisuje, jak przepisać nazwy znaczników. Filtr catto operacja tożsamości. Twoje repozytorium, podobnie jak powyższy przykład, może nie zawierać żadnych tagów, ale dodałem tę opcję dla pełnej ogólności.
-- określa koniec opcji dla git filter-branch
--allnastępujące --jest skrótem dla wszystkich referencji. Twoje repozytorium, podobnie jak powyższy przykład, może mieć tylko jeden odnośnik (master), ale włączam tę opcję dla pełnej ogólności.
Po krótkiej przerwie historia jest teraz:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A login.html
| * cb14efd Remove DVD-rip
| | D oops.iso
| * ce36c98 Careless
|/ A oops.iso
| A other.html
|
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Zauważ, że nowe zatwierdzenie „Nieostrożne” dodaje tylko other.htmli że zatwierdzenie „Usuń DVD-rip” nie jest już w gałęzi master. Oddział oznaczony refs/original/refs/heads/masterzawiera oryginalne zatwierdzenia na wypadek pomyłki. Aby go usunąć, wykonaj czynności opisane w „Liście kontrolnej zmniejszania repozytorium”.
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
Dla prostszej alternatywy sklonuj repozytorium, aby odrzucić niechciane bity.
$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo
Użycie file:///...sklonowanego adresu URL powoduje kopiowanie obiektów zamiast tworzenia wyłącznie linków stałych.
Teraz twoja historia to:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Nazwy obiektów SHA1 dla pierwszych dwóch zatwierdzeń („Indeks” i „Strona administratora”) pozostały takie same, ponieważ operacja filtrowania nie zmodyfikowała tych zatwierdzeń. „Nieostrożny” stracił, oops.isoa „Strona logowania” ma nowego rodzica, więc ich SHA1 się zmieniły.
Interaktywna baza danych
Z historią:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
chcesz usunąć oops.isoz „Nieostrożnego”, jakbyś nigdy go nie dodał, a wtedy „Usuń DVD-rip” jest dla ciebie bezużyteczne. Dlatego naszym planem przejścia na interaktywny rebase jest utrzymanie „Strony administracyjnej”, edycja „Nieostrożny” i odrzucenie „Usuń DVD-rip”.
Uruchamianie $ git rebase -i 5af4522uruchamia edytor o następującej treści.
pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Realizując nasz plan, modyfikujemy go do
edit ce36c98 Careless
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
# ...
Oznacza to, że usuwamy wiersz za pomocą polecenia „Remove DVD-rip” i zmieniamy operację na „Careless” na editzamiast pick.
Opuszczenie edytora powoduje wyświetlenie wiersza polecenia z następującym komunikatem.
Stopped at ce36c98... Careless
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Jak mówi nam wiadomość, wykonujemy zatwierdzenie „Nieostrożne”, które chcemy edytować, więc uruchamiamy dwa polecenia.
$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue
Pierwszy usuwa szkodliwy plik z indeksu. Drugi modyfikuje lub zmienia „Nieostrożny”, aby był zaktualizowanym indeksem i -C HEADinstruuje git, aby ponownie użył starej wiadomości zatwierdzenia. Wreszcie, git rebase --continuekontynuuje resztę operacji rebase.
To daje historię:
$ git lola --name-status
* 93174be (HEAD, master) Login page
| A login.html
* a570198 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
co chcesz.