Można rzeczywiście użyć filtra podkatalogu, po którym następuje filtr indeksu, aby umieścić zawartość z powrotem w podkatalogu, ale po co zawracać sobie głowę, gdy można po prostu użyć samego filtra indeksu?
Oto przykład ze strony człowieka:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
To tylko usuwa jednego pliku; to, co chcesz zrobić, to usunąć wszystko oprócz podanego podkatalogu. Jeśli chcesz być ostrożnym, można jawnie wymienić każdą ścieżkę do usuwania, ale jeśli chcesz po prostu iść all-in, można po prostu zrobić coś takiego:
git filter-branch --index-filter 'git ls-tree -z --name-only --full-tree $GIT_COMMIT | grep -zv "^directory-to-keep$" | xargs -0 git rm --cached -r' -- --all
Spodziewam się tam pewnie bardziej elegancki sposób ; jeśli ktokolwiek coś ma, sugeruj to!
Kilka uwag na temat tego polecenia:
- filtra oddział wewnętrznie wyznacza GIT_COMMIT do prądu popełnić SHA1
- bym nie oczekiwano
--full-tree
być konieczne, ale widocznie filtrować-gałąź biegnie indeks -filter z katalogu .git-rewrite/t
zamiast najwyższego poziomu repozytorium.
- grep to prawdopodobnie przesada, ale nie sądzę, że jest to problem z szybkością.
--all
stosuje się do wszystkich informacji; Myślę, że naprawdę tego chcesz. (--
oddziela go od opcji gałęzi filtru)
-z
i -0
powiedz ls-tree, grep i xargs, aby używały terminacji NUL do obsługi spacji w nazwach plików.
Edytuj, znacznie później: Thomas zasugerował sposób usunięcia pustych już zatwierdzeń, ale jest już nieaktualny. Spójrz na historii edycji jeśli masz starą wersję git, ale z nowoczesnym git, wszystko co musisz zrobić, to przyczepność na tej opcji:
--prune-empty
To będzie usunąć wszystkie rewizje, które są puste po zastosowanie filtra indeksu.
Oprócz zagnieżdżonych pojedynczych cytatów (które mogłem zastąpić), działało prawie idealnie. Jedynym problemem było to, że puste wpisy do nieistniejących katalogów pozostały w dzienniku. Usunąłem je za pomocą 'git filter-branch -f --commit-filter ', jeśli [z $ 1 = z \' git rev-parse $ 3^{tree} \ ']; następnie skip_commit "$ @"; else git commit-tree "$ @"; fi '"$ @" ', które znalazłem na http://github.com/jwiegley/git-scripts/blob/master/git-remove-empty-commits – Thomas
@Thomas: Dzięki za naprawienie mojego nieostrożnego błędu! Ponadto powinieneś być w stanie użyć filtra zatwierdzania w tej samej komendzie, co filtr indeksu. Filtry są uruchamiane w kolejności pokazanej w dokumentacji; commit-filter jest naturalnie po filtrach, które modyfikują zawartość commit. Prawdopodobnie chcesz również użyć '--remap-to-ancestor', co spowoduje, że referencje, które wskazują pominięte zatwierdzenia, zostaną przeniesione do najbliższego przodka zamiast ich wykluczenia. – Cascabel
@Jefromi: argument 'index-filter' powinien być łatwiej wyrażalny jako' git rm -r -f --cached --ignore-unmatch $ (ls! (Directory-to-keep)) ', zobacz moje odpowiedzi http : //stackoverflow.com/a/8079852/396967 i http://stackoverflow.com/a/7849648/396967 – kynan