Jak naprawić poddrzewo git po zepchnięciu siły projektu z góry na master?

13

Eksperymentowałem z użyciem poddrzewa git i napotkałem następującą sytuację.

Użyłem poddrzewa git, aby dodać zewnętrzny projekt do mojego repozytorium, celowo zachowałem całą historię dla projektu wyższego szczebla, ponieważ chcę móc odwoływać się do historii projektu, a także później wnieść swój wkład do projektu wyższego szczebla.

Jak się okazuje, inny współpracownik projektu upstream przypadkowo wypchnął duży plik do gałęzi master. Aby to naprawić, poprzedni projekt przepisał historię i wymusił przekazanie jej na master. Tworząc moje „monorepo”, załączyłem ten zatwierdzenie i chciałbym go również usunąć.

Jak mogę zaktualizować moje repozytorium, aby odzwierciedlić nową historię poddrzewa?

Moja pierwsza próba polegała na użyciu gałęzi filter do całkowitego usunięcia poddrzewa i całej historii.

git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch upstream-project-dir' --prune-empty HEAD

Po usunięciu starej wersji poddrzewa mogłem ponownie dodać poddrzewo, korzystając z nowego wzorca głównego. Jednak to nie zadziałało, ponieważ z jakiegoś powodu historia zatwierdzeń nadal pojawia się w danych wyjściowych dziennika git.

Aktualizacja

Napisałem kroki, aby stworzyć przykład w minimalnym stopniu powtarzalny.

  1. Najpierw utwórz puste repozytorium git.

    git init test-monorepo
    cd ./test-monorepo
    
  2. Utwórz początkowe zatwierdzenie.

    echo hello world > README
    git add README
    git commit -m 'initial commit'
    
  3. Teraz dodaj poddrzewo dla projektu zewnętrznego.

    git remote add thirdparty [email protected]:teivah/algodeck.git
    git fetch thirdparty
    git subtree add --prefix algodeck thirdparty master
    
  4. Dokonaj kilku zmian na monorepo

    echo dont panic >> algodeck/README.md
    git commit -a -m 'test commit'
    
  5. Teraz spróbuj użyć git filter-branch, aby usunąć poddrzewo.

    git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
    
  6. Sprawdź dane wyjściowe dziennika git, oczekuję, że zobaczę tylko moje początkowe zatwierdzenie.

    git log
    
csnate
źródło
Czy próbowałeś użyć gc --prune = teraz, aby wyrzucić stare zmiany? Czy są jakieś odniesienia do zatwierdzeń starej wersji?
Damiano
1
Nie próbowałem tego jeszcze, ale nie git gc --prune=nowusunę tylko zatwierdzeń, które się nie pojawiają git log?
csnate
użycie git branch -all (które, jak przypuszczam, używasz, aby zobaczyć „stare” commits) powinno pokazywać również commity niezwiązane z bieżącą gałęzią.
Damiano,
1
Właściwie to po prostu robiłem git log, bez argumentów i wciąż widzę stare zobowiązania.
csnate
Czy możesz opublikować swój dziennik git --pretty --all --graph? Żeby zrozumieć twoją sytuację
Damiano,

Odpowiedzi:

0

masz już złe zatwierdzenie w swojej historii i musisz się go pozbyć, zanim przejdziesz dalej

załóżmy, że zostałeś masterostatnio przekierowany i nie mogłeś nic zrobić (tak naprawdę nie mam twoich gałęzi w zasięgu wzroku, więc muszę założyć coś na początek)

możesz przejść do poprzedniego zatwierdzenia i przesunąć znacznik gałęzi o 1 krok do tyłu (lub X kroków do tyłu), co w każdym razie byłoby nieszkodliwe, a następnie pociągnąć ponownie

na przykład

git checkout master~1
git branch master -f
git checkout master
git pull
  1. git checkout master~1 aby sprawdzić, czy rodzic zatwierdził, git ostrzega, że ​​nie mamy oddziałów
  2. git branch master -f aby zmusić bieżącą kasę, aby ponownie stała się master, tj. faktycznie przewija gałąź master do poprzedniego zatwierdzenia (lub X poprzedniego zatwierdzenia), i stąd nie ma znaczenia, czy poprzednio wykonał siłę, czy nie, możemy wznowić normalnie, a nawet w razie potrzeby wróć do powyższego kroku, możemy tylko ponownie przyciągnąć mistrza, nie tracąc niczego z góry (co dla nas może być również tylko do odczytu, nie będziemy naciskać na to)
  3. git checkout master aby znaleźć się w naszej „przewiniętej” gałęzi master, to samo zatwierdzenie, do którego wkraczamy, ale teraz będąc w gałęzi
  4. git pullaby ponownie przyciągnąć mistrza (może być z lub bez --prune), jeśli zostanie skierowane w górę rzeki, wrócimy stąd na ścieżkę, jeśli nie, otrzymamy to samo, co mieliśmy, jeśli otrzymamy to samo i nie przypuszczaliśmy, być może muszę wrócić do pierwszego kroku powyżej i przewinąć więcej zatwierdzeń, np. git checkout master~5lub cokolwiek (w razie potrzeby)
arhak
źródło
Nie sądzę, żeby to zadziałałogit subtree
csnate
@csnate można wyrejestrować poprzednie zatwierdzenia z subrepo i postępować zgodnie z bardzo podobną procedurą, jeśli zbudujesz MCVE, łatwiej będzie ci powiedzieć dokładne polecenia do wykonania przez stackoverflow.com/help/minimal-reproducible-example
arhak
Spróbuję utworzyć przykładowe repozytorium na GitHub.
csnate
Stworzyłem zestaw kroków w oryginalnym pytaniu, które pokazuje problem.
csnate
0
  1. w repozytorium oczyść historię zatwierdzeń dla tego pilota:

    git fetch upstream
    
  2. jeśli jeden z twoich zatwierdzeń ma zatwierdzenie, które zawiera duży plik, przepisz swoją historię, aby ten duży plik nie był już przywoływany

    # using one or more of the following commands :
    git rebase --interactive
    git filter-branch
    ...
    

W tych dwóch krokach do dużego pliku nie będzie już odwoływać się żadne zatwierdzenie w repozytorium.
Zostanie on dodatkowo usunięty z twojego dysku twardego w pewnym momencie, kiedy git uruchomi swój moduł wyrzucania elementów bezużytecznych i osiągnięte zostaną opóźnienia wygasania dla wiszących obiektów blob.


Jeśli masz pilną potrzebę jak najszybszego usunięcia tego dużego pliku z dysku twardego:

Uruchom ręcznie

git gc --prune=now
LeGEC
źródło