To, co chcesz zrobić, jest bardzo destrukcyjne, jeśli opublikujesz historię innym programistom. Zobacz „Odzyskiwanie z wcześniejszego uruchomienia” w git rebase
dokumentacji, aby dowiedzieć się, jakie kroki należy wykonać po naprawieniu historii.
Masz co najmniej dwie opcje: git filter-branch
i 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 lola
jest to niestandardowy, ale bardzo użyteczny alias. Za pomocą --name-status
przełą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.iso
to 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-empty
usuwa zatwierdzenia, które stają się puste ( tj. nie zmieniają drzewa) w wyniku operacji filtrowania. W typowym przypadku ta opcja zapewnia czystszą historię.
-d
nazywa 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/shm
spowoduje szybsze wykonanie .
--index-filter
jest głównym wydarzeniem i działa na podstawie indeksu na każdym etapie historii. Chcesz usunąć, oops.iso
gdziekolwiek się znajdzie, ale nie jest obecny we wszystkich zatwierdzeniach. Polecenie git rm --cached -f --ignore-unmatch oops.iso
usuwa zgrywanie DVD, gdy jest obecne, i w przeciwnym razie nie zawiedzie.
--tag-name-filter
opisuje, jak przepisać nazwy znaczników. Filtr cat
to 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
--all
nastę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.html
i że zatwierdzenie „Usuń DVD-rip” nie jest już w gałęzi master. Oddział oznaczony refs/original/refs/heads/master
zawiera 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.iso
a „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.iso
z „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 5af4522
uruchamia 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 edit
zamiast 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 HEAD
instruuje git, aby ponownie użył starej wiadomości zatwierdzenia. Wreszcie, git rebase --continue
kontynuuje 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.