2013-07-26 10 views
7

Scenariusz jest następujący:git filtr-branch doprowadził do rozłączonej historii: jak pozbyć się starych zobowiązań?

Mam duże repozytorium CVS, które chcę przekonwertować na 14 odrębnych repozytoriów git. Część procesu jest w porządku i prowadzi do repo.git dużego repozytorium.

Dla każdego z repo 14 git, ja sklonować głównego repo i uruchom następujące polecenie:

git filter-branch -d /tmp/rep --tag-name-filter cat --prune-empty --subdirectory-filter "sub/directory" -- --all 

Jednakże przed tym poleceniu muszę wykonać kolejne polecenie git filter-branch dla niektórych repozytoriów git ponieważ Muszę przepisać zatwierdzenia, aby przenieść plik z katalogu do innego. --tree-filter jest opcją, której używam. Oto przykład z wiersza poleceń wykonywane:

script_tree_filter="if test -f rep/to/my/file && test -d another/rep ; then echo Moving my file ; mv rep/to/my/file another/rep; fi" 
git filter-branch -d /tmp/rep --tag-name-filter cat --prune-empty --tree-filter '$script_tree_filter' -- --all 

Pod koniec procesu (14500 commity: trwa około 1 godziny!) Czyścić sędziowie i używać git gc:

git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d 
git reflog expire --expire=now --all 
git gc --prune=now 

Na na koniec dostaję repozytorium o wielkości 1.2Go (co oczywiście jest wciąż zbyt duże), a patrząc na zatwierdzenia, widzę, że wiele starych wciąż jest obecnych. Dotyczą plików i katalogów, których nie powinno już tu być po komendzie --subdirectory-filter.

W historii zobowiązuje, nie ma ciągłości między niechcianych zatwierdzeń i tych dobrych, jak widać na gitk --all:

discontinuity seen in gitk

Jestem prawie pewien, że te rewizje są nadal obecne ze względu na tagi na niektórych na nich. Jeśli tak, to czy możliwe jest usunięcie tych tagów bez usuwania tego na dobrym zatwierdzeniu?

Jeśli tagi nie są powodem, żadnego pomysłu?

Aby uzyskać więcej informacji, zawartość katalogu refs (w repozytorium git podkatalogu uzyskanych przez filtr) jest pusta:

$ ls -R refs/ 
refs/: 
heads original tags 

refs/heads: 

refs/original: 
refs 

refs/original/refs: 
heads tags 

refs/original/refs/heads: 

refs/original/refs/tags: 

refs/tags: 

Odkryłam, że gałęzie i tagi są wymienione w pliku packed-refs w repozytorium git:

d0c675d8f198ce08bb68f368b6ca83b5fea70a2b refs/tags/v03-rev-04 
95c3f91a4e92e9bd11573ff4bb8ed4b61448d8f7 refs/tags/v03-rev-05 

W pliku znajduje się 817 znaczników i 219 gałęzi.

+1

'git gc' zapakuje tag refs do .git/packed-refs, stąd puste katalogi. Nie jestem pewien, dlaczego znaczniki wskazywałyby na stare zatwierdzenia, biorąc pod uwagę, że każda operacja filtru-op używała '--tag-name-filter' ... – torek

+1

Czy sprzątałeś zgodnie z 4 poleceniami tego wpisu ?http://stackoverflow.com/a/7966852/11343 – CharlesB

+0

Oprócz 'reset hard', zrobiłem polecenie 3 innych, jak wspomniano w moim pytaniu (' rm -rf .git/refs/original/'nie jest napisane w ten sam sposób, ponieważ mam puste repozytorium). Nie użyłem opcji '--agressive' gc, ale nie mogę spróbować (nie sądzę, żeby to zmieniło cokolwiek). – Frodon

Odpowiedz

5

Udało mi się rozwiązać problem zmieniając sposób, w jaki użyłem cvs2git: zamiast konwersji całej bazy CVS, a następnie użyj polecenia subdirectory-filter, skonwertowałem każdy z submodułów, które chciałem. W moim przypadku, to doprowadziło do uruchomienia 18 różnych cvs2git polecenia:

Przed

cvs2git --blobfile=blob --dump=dump /path/to/cvs/base 
# Module 1 
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter "path/to/module1" -- --all 
# Module 2 
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter "path/to/module2" -- --all 

Teraz

# Module 1 
cvs2git --blobfile=blob_module1 --dump=dump_module1 /path/to/cvs/base/path/to/module1 
# Module 2 
cvs2git --blobfile=blob_module2 --dump=dump_module2 /path/to/cvs/base/path/to/module2 

Każde repozytorium ma teraz doskonałą historię.

Dlaczego poprzednia metoda nie działała? Domyślam się, że cvs2git został zmylony ze wszystkimi submodułami (niektóre z nich miały zmienioną nazwę katalogu podczas ich historii).

@Michael @CharlesB Dziękujemy za poświęcenie czasu, aby odpowiedzieć i mi pomóc.

+1

+1 za udostępnienie rozwiązania, cieszę się, że go rozwiązałeś – CharlesB

+1

@CharlesB: dziękuję za wsparcie – Frodon

+2

Cieszę się, że to rozwiązałeś, byłem ciekawy, dlaczego robiłeś duże repozytorium od samego CVS - niesamowite, że podzieliłeś się rozwiązanie - okrzyki. +1 również – Michael

2

Założę się trafiony z tym:

  • Różnice między CVS i git modeli oddział/Tag: CVS pozwala oddział lub tag być tworzone z dowolnych kombinacjach wersjami źródłowych z wielokrotnym źródła gałęzie. Pozwala nawet na zmiany plików, które nigdy nie były dodawane jednocześnie do pojedynczej gałęzi/znacznika. Z drugiej strony Git zezwala tylko na pełne drzewo źródłowe, tak jak istniało w jakimś momencie historii, na rozgałęzienie lub oznaczenie jako jednostkę. Co więcej, pochodzenie wersji git powoduje implikacje dotyczące zawartości tej wersji. Ta różnica oznacza, że ​​zasadniczo niemożliwe jest wierne odtworzenie dowolnej historii CVS w repozytorium git w 100%.cvs2git wykorzystuje następujące rozwiązania:

    • cvs2git próbuje utworzyć oddział z jednego źródła, ale jeśli nie może dowiedzieć się, jak tworzy gałąź pomocą „scalić” z wielu gałęziach źródłowych. W sytuacjach patologicznych liczba źródeł scalania dla oddziału może być dowolnie duża. Wynikowa historia oznacza, że ​​po dodaniu dowolnego pliku do oddziału cała gałąź źródłowa została scalona w gałąź docelową, co jest oczywiście niepoprawne. (Alternatywa, aby pominąć scalanie, odrzuciłaby informację, że niektóre treści zostały przeniesione z jednego oddziału do drugiego.)

    • Jeśli cvs2git nie może określić, że tag CVS może zostać utworzony z pojedynczej wersji, to tworzy gałąź z tagami fixup o nazwie TAG.FIXUP, a następnie oznacza tę gałąź. (Jest to konieczne obejście tego, że git pozwala tylko na oznaczanie istniejących wersji.) Gałąź TAG.FIXUP jest tworzona jako scalenie wszystkich gałęzi, które zawierają wersje plików zawarte w tagu, który obejmuje ten sam opis wymiany, powyżej dla oddziałów. Oddział TAG.FIXUP jest czyszczony na końcu konwersji, ale (ze względu na techniczne ograniczenie formatu pliku szybkiego importu git) nie został usunięty. Istnieją sytuacje, w których można utworzyć znacznik z jednej wersji, ale cvs2git nie zdaje sobie z tego sprawy i tworzy niepotrzebną gałąź fixów tagów. Możliwe jest usunięcie zbędnych gałęzi fixów tagów po konwersji przez uruchomienie skryptu contrib/git-move-refs.py w wynikowym repozytorium git.

  • Nie ma żadnych kontroli, czy nazwy gałęzi i znaczników CVS są legalnymi nazwami git. Są prawdopodobnie inne ograniczenia git, które również powinny zostać sprawdzone. see cvs2git

Czy pokazując katalog pozycje literatury nowych katalogów lub o dużym repo po konwersji? Możesz usunąć tagi w jednym dużym repo wywozu, zanim odfiltrujesz i podzielisz duże repozytorium.

Możesz usunąć znaczniki w dużym repo po prostu usuwając pliki z katalogu - to tylko odwołanie do SHA.

+0

Katalog refs jest katalogiem nowego katalogu (po podkatalogu filter). Usunięcie wszystkich tagów nie jest opcją: chcę zachować te, które dotyczą katalogów, które przechowuję. – Frodon

+0

Nie powiedziałem, że należy usunąć wszystkie znaczniki, po prostu usuń nieważne = mówiliście, że niektóre niepotrzebne znaczniki powodują problemy. – Michael

+0

Sztuką jest to, że nie wiem, jak odróżnić "dobre" tagi od "złych". Obecnie badam, czy usunąć puste zatwierdzenia z tagami. – Frodon

Powiązane problemy