2011-09-07 9 views
11

Jestem w trakcie rozdzielania starego zestawu aplikacji, które pierwotnie znajdowały się w jednym repozytorium Subversion.Jak usunąć wszystkie pliki w repozytorium Git, które nie znajdują się w katalogu roboczym?

Przekonwertowałem go do repozytorium Git i usunąłem to, czego nie chcę, ale chciałbym schudnąć repozytorium poprzez pozbycie się historycznych danych związanych z usuniętymi plikami (oryginalne repozytorium będzie być utrzymywane dla celów referencyjnych, więc nie jest potrzebne w nowym).

Idealnie chciałbym przejść przez całe repozytorium i usunąć wszystkie pliki lub foldery nieobecne w katalogu roboczym wraz z powiązaną z nimi historią. To zostawiłoby mnie z treścią HEAD i historią commitów mających wpływ na te pliki. Jednak nie znalazłem sposobu na zrobienie tego (osierocenie HEAD nie pomaga, ponieważ nie chroni historii).

Czy to możliwe? Wiem, jak usunąć pojedynczy plik lub folder z całej historii za pomocą git-filter-branch, ale jest zbyt wiele plików i folderów, aby było to praktyczne podejście ... chyba że istnieje sposób na filtrowanie wszystkich plików nie w HEAD ?

+0

Co o plikach został przemianowany w przeszłości? Rozwiń historię po zmianie nazwy lub zachowaj jej zmianę (i śledź inną nazwę pliku przed zmianą nazwy). – knittl

+0

Dobra uwaga. Wolałbym zachować historię przed zmianą nazwy, więc musiałbym mieć kilka dodatkowych plików, które są w porządku. –

Odpowiedz

3

Zrobiłem to kilka razy - wypakowanie zatwierdza pojedynczy plik i tworzy z niego nowe repozytorium. Wygląda to mniej więcej tak:

$ c=10; for commit in $(git log --format=%h -- path/to/file|tac); do 
     c=$((c+1)) 
     git format-patch -1 --stdout $commit > $c.patch 
    done 

Spowoduje to utworzenie plików łat 11patch, 12.patch i tak dalej. Następnie edytuję te łatki (używając vima lub perla, które wydają się najlepsze dla danego zadania), usuwając całe porcje dla plików, które mnie nie interesują, i może naprawię nazwy również w przypadku nazw w nagłówku diff hunk.

Używam git am na łatkach na nowym repozytorium git. Jeśli coś nie pojawi się w tym momencie, odpieram nowe repozytorium git i ponownie edytuję łatki i powtarzam git am.

Powodem rozpocząć odliczanie od 10 to dlatego, że jestem leniwy, aby poprzedzić wiodącą 0 do sekwencji patch dla popełnia więcej niż 99 właśnie zaczynają się od 99.

+0

można użyć '$ (printf"% 02d "$ c) .patch', aby wyprzedzić początkowe zero. – jfs

+0

Dzięki za wzmiankę o tym. Odtąd muszę częściej używać printf. – holygeek

+0

Dzięki ... ale czy to nie działa na podstawie pliku po pliku? Jak już powiedziałem w moim pytaniu, wiem, jak to zrobić na podstawie pliku, ale jest zbyt wiele plików, aby było to praktyczne. A może nie rozumiem, co się tutaj dzieje? –

6

Oto jak można użyć git Filtry gałąź, aby pozbyć się wszystkich plików, które nie chcą:

  1. Uzyskaj listę nazw, które nie chcą się pojawić w historii zarówno stare nazwy i nowe nazwy w przypadku zmienia nazwę . Na przykład umieścić je w pliku o nazwie toberemoved.txt

  2. Run git branży filtracyjnej tak:

    $ git filter-branch --tree-filter "rm -f `cat toberemoved.txt`" branch1 branch2 ... 
    

Oto odpowiednią stronę mężczyzna z filtrem-git oddziału:

--tree-filter <command> 
     This is the filter for rewriting the tree and its contents. The 
     argument is evaluated in shell with the working directory set to 
     the root of the checked out tree. The new tree is then used as-is 
     (new files are auto-added, disappeared files are auto-removed - 
     neither .gitignore files nor any other ignore rules HAVE ANY 
     EFFECT!). 

Po prostu upewnij się, że lista plików, które chcesz usunąć, jest względna względem katalogu głównego wyeksportowanego drzewa.

Aktualizacja:

Aby uzyskać listę plików, które były obecne w przeszłości, ale nie w bieżącym katalogu roboczym można uruchomić następujące.Zauważ, że musisz zrobić dalsze wysiłki, aby utrzymać „historię przed zmianą nazwy” z przemianowany plików:

$ git log --raw |awk '/^:/ { if (! printed[$6]) { print $6; printed[$6] = 1 }}'|while read f;do if [ ! -f $f ]; then echo Deleted: $f;fi;done 

To $ 6 jest nazwa pliku, które zostały dotknięte w sposób pokazany w popełnić w --raw tryb dziennika.

Zobacz opcję --diff-filter do dziennika git, jeśli chcesz wiedzieć, co się stało ([D] eleted, [R] enamed, [M] odified, i tak dalej) do każdego pliku dla każdego zatwierdzenia.

Być może inni mogą podpowiedzieć, jak znaleźć poprzednią nazwę śledzonego pliku w przypadku zmiany nazwy.

+0

Dzięki za nową odpowiedź. Zbliżając się myślę, że nie myślałem o używaniu 'cat' z filtrem. Trochę nie dostaję jednak, jak wygenerować listę plików, biorąc pod uwagę, że jestem zainteresowany tylko usunięciem plików * nie * w katalogu roboczym (a zatem nie jest łatwo dostępny do listy). Jakieś dalsze pomysły? –

+0

Zaktualizowałem odpowiedź, aby dołączyć polecenie, aby uzyskać listę usuniętych plików. – holygeek

+0

Dobra odpowiedź. Usunąłem 'Deleted:' z Oneliner, aby uzyskać listę. Ale podczas korzystania z tej listy, z jakiegoś powodu składnia bash w poleceniu branch-git git nie działa. Zamiast tego użyłem 'git filter-branch --tree-filter" cat $ HOME/toberemoved.txt | xargs -I {} rm -f {} "' (Zauważ, że 'toberemoved.txt' musi znajdować się poza katalogiem pod kontrolą wersji.Może to spowodowało problem ze składnią '" cat 'toberemoved.txt'" ', ale nie sprawdziłem.) – jaimedash

1

Pomaganie w drugiej odpowiedzi: "Może inni mogą wtrącić jak znaleźć poprzednią nazwę śledzonego pliku w przypadku zmiany nazwy."

Spowoduje to zwrócenie plików w projekcie i plików, z których zostały zmienione.

for file in `git ls-files`; do git log --follow --name-only --pretty=format: $file | sort -n -b | uniq | sed '/^\s*$/d'; done

Można ich używać do wykluczenia z listy.

Całe rozwiązanie jest:

for file in `git ls-files`; do git log --follow --name-only --pretty=format: $file | sort -n -b | uniq | sed '/^\s*$/d'; done > current.txt

git log --raw |awk '/^:/ { if (! printed[$6]) { print $6; printed[$6] = 1 }}'|while read f;do if [ ! -f $f ]; then echo $f;fi;done | sort > hist.txt

diff --new-line-format="" --unchanged-line-format="" hist.txt current.txt > for_remove.txt

Powiązane problemy