Wie repariere ich einen Git-Teilbaum, nachdem die vorgelagerte Projekttruppe auf den Master geschoben wurde?


13

Ich habe mit der Verwendung des Git-Teilbaums experimentiert und bin auf die folgende Situation gestoßen.

Ich habe den Teilbaum git verwendet, um meinem Repo ein externes Projekt hinzuzufügen. Ich habe absichtlich den gesamten Verlauf für das Upstream-Projekt beibehalten, da ich auf den Verlauf des Projekts verweisen und später auch einen Beitrag zum Upstream-Projekt leisten möchte.

Wie sich herausstellt, hat ein anderer Mitarbeiter des Upstream-Projekts versehentlich eine große Datei in den Hauptzweig verschoben. Um dies zu beheben, hat das vorgelagerte Projekt den Verlauf neu geschrieben und den Master erzwungen. Bei der Erstellung meines "Monorepo" habe ich dieses Commit eingefügt und möchte es auch entfernen.

Wie kann ich mein Repository aktualisieren, um den neuen Verlauf des Teilbaums widerzuspiegeln?

Mein erster Versuch war, Filter-Branch zu verwenden, um den Teilbaum und den gesamten Verlauf vollständig zu entfernen.

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

Sobald die alte Version des Teilbaums entfernt wurde, konnte ich den Teilbaum mit dem neuen Upstream-Master erneut hinzufügen. Dies hat jedoch nicht funktioniert, da der Festschreibungsverlauf aus irgendeinem Grund immer noch in der Git-Protokollausgabe angezeigt wird.

Aktualisieren

Ich habe die Schritte geschrieben, um ein minimal reproduzierbares Beispiel zu erstellen.

  1. Erstellen Sie zuerst ein leeres Git-Repo.

    git init test-monorepo
    cd ./test-monorepo
    
  2. Erstellen Sie ein erstes Commit.

    echo hello world > README
    git add README
    git commit -m 'initial commit'
    
  3. Fügen Sie nun einen Teilbaum für ein externes Projekt hinzu.

    git remote add thirdparty git@github.com:teivah/algodeck.git
    git fetch thirdparty
    git subtree add --prefix algodeck thirdparty master
    
  4. Machen Sie einige Commits auf dem Monorepo

    echo dont panic >> algodeck/README.md
    git commit -a -m 'test commit'
    
  5. Versuchen Sie nun, den Teilbaum mit git filter-branch zu entfernen.

    git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
    
  6. Untersuchen Sie die Git-Protokollausgabe. Ich erwarte nur mein erstes Commit.

    git log
    

Haben Sie versucht, gc --prune = jetzt zu git, um die alten Commits wegzuwerfen? Gibt es einige Verweise auf die Commits der alten Version?
Damiano

1
Ich habe dies noch nicht versucht, aber nicht git gc --prune=nownur Commits gelöscht, die nicht in git logangezeigt werden.
csnate

Wenn Sie git branch -all verwenden (ich nehme an, Sie verwenden es, um die "alten" Commits anzuzeigen), sollten auch die Commits angezeigt werden, die nicht mit Ihrem aktuellen Zweig zusammenhängen.
Damiano

1
Eigentlich habe ich nur git logkeine Argumente gemacht und ich sehe immer noch die alten Commits.
csnate

Kannst du bitte dein Git Log --pretty --all --graph posten? Nur um Ihre Situation zu verstehen
Damiano

Antworten:


0

Sie haben bereits das schlechte Commit in Ihrer Geschichte und müssen es loswerden, bevor Sie fortfahren können

Nehmen wir an, Sie haben das masterletzte Commit umgeleitet und konnten nichts anderes tun (ich habe Ihre Filialen wirklich nicht in Sicht, also muss ich zunächst etwas annehmen).

Sie können zum vorherigen Commit auschecken und Ihre Verzweigungsmarkierung 1 Schritt zurück (oder X Schritte zurück) drücken, was in jedem Fall harmlos wäre, und dann erneut ziehen

z.B

git checkout master~1
git branch master -f
git checkout master
git pull
  1. git checkout master~1 Um das übergeordnete Commit des Masters auszuchecken, warnt Git, dass wir nicht in den Filialen sind
  2. git branch master -f Um die aktuelle Prüfung zu zwingen, wieder Master zu werden, dh den Master-Zweig tatsächlich auf sein vorheriges Commit (oder X vorheriges Commit) zurückzuspulen, und von hier aus spielt es keine Rolle, ob der Upstream eine Force ausgeführt hat oder nicht, wir können normal oder sogar fortfahren Gehen Sie bei Bedarf zum obigen Schritt zurück. Wir können den Master nur wieder ziehen, ohne etwas vom Upstream zu verlieren (was für uns auch schreibgeschützt sein könnte, wir werden nichts dafür tun).
  3. git checkout master Um in unserer "zurückgespulten" Hauptniederlassung zu sein, das gleiche Commit, auf das wir treten, aber jetzt stattdessen in der Niederlassung
  4. git pullUm den Master wieder zu ziehen (kann mit oder ohne sein --prune), werden wir von hier aus wieder auf die Strecke zurückkehren, wenn nicht, werden wir das Gleiche bekommen, das wir hatten, wenn wir das Gleiche bekamen und nicht angenommen wurden, vielleicht wir Sie müssen zum ersten Schritt oben zurückkehren und weitere Commits zurückspulen, z. B. git checkout master~5oder was auch immer (je nach Bedarf).

Ich glaube nicht, dass dies mitgit subtree
csnate

@csnate Es ist möglich, frühere Commits aus einem Subrepo auszuchecken und einem sehr ähnlichen Verfahren zu folgen. Wenn Sie ein MCVE erstellen, ist es einfacher, Ihnen die genauen Befehle zu nennen, denen Sie folgen sollen. stackoverflow.com/help/minimal-reproducible-example
arhak

Ich werde versuchen, ein Beispiel-Repo auf GitHub zu erstellen.
csnate

Ich habe in der ursprünglichen Frage eine Reihe von Schritten erstellt, die das Problem zeigen.
csnate

0
  1. Bereinigen Sie in Ihrem Repo den Verlauf der Commits für diese Fernbedienung:

    git fetch upstream
    
  2. Wenn einer Ihrer eigenen Commits einen Commit enthält, der die große Datei enthält, schreiben Sie Ihren Verlauf neu, sodass auf diese große Datei nicht mehr verwiesen wird

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

Mit diesen beiden Schritten wird die große Datei von keinem Commit in Ihrem Repo mehr referenziert.
Es wird außerdem zu einem bestimmten Zeitpunkt zusätzlich von Ihrer Festplatte gelöscht, wenn git seinen Garbage Collector ausführt und die Ablaufverzögerungen für baumelnde Blobs erreicht sind.


Wenn Sie diese große Datei dringend so schnell wie möglich von Ihrer Festplatte löschen müssen:

Manuell ausführen

git gc --prune=now
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.