Es gibt zwei Schritte, um dies zu erreichen:
- Erstellen Sie ein neues leeres Commit
- Schreiben Sie den Verlauf neu, um mit diesem leeren Commit zu beginnen
Wir werden das neue leere Commit der Einfachheit halber in einen temporären Zweig stellen newroot
.
1. Erstellen Sie ein neues leeres Commit
Es gibt verschiedene Möglichkeiten, dies zu tun.
Verwenden Sie nur Sanitär
Der sauberste Ansatz besteht darin, Git's Sanitär zu verwenden, um direkt ein Commit zu erstellen, wodurch vermieden wird, dass die Arbeitskopie oder der Index berührt wird oder welcher Zweig ausgecheckt wird usw.
Erstellen Sie ein Baumobjekt für ein leeres Verzeichnis:
tree=`git hash-object -wt tree --stdin < /dev/null`
Wickeln Sie ein Commit darum:
commit=`git commit-tree -m 'root commit' $tree`
Erstellen Sie einen Verweis darauf:
git branch newroot $commit
Sie können den gesamten Vorgang natürlich in einen Einzeiler umwandeln, wenn Sie Ihre Shell gut genug kennen.
Ohne Sanitär
Mit regulären Porzellanbefehlen können Sie newroot
ohne guten Grund kein leeres Commit erstellen, ohne den Zweig auszuchecken und den Index und die Arbeitskopie wiederholt zu aktualisieren. Einige mögen dies jedoch leichter verstehen:
git checkout --orphan newroot
git rm -rf .
git clean -fd
git commit --allow-empty -m 'root commit'
Beachten Sie, dass Sie bei sehr alten Versionen von Git, denen der --orphan
Wechsel zu fehlt checkout
, die erste Zeile durch folgende ersetzen müssen:
git symbolic-ref HEAD refs/heads/newroot
2. Schreiben Sie den Verlauf neu, um mit diesem leeren Commit zu beginnen
Sie haben hier zwei Möglichkeiten: Neubasieren oder ein sauberes Umschreiben des Verlaufs.
Wiederherstellen
git rebase --onto newroot --root master
Dies hat den Vorteil der Einfachheit. Es werden jedoch auch der Name und das Datum des Committers bei jedem letzten Commit in der Verzweigung aktualisiert.
Bei einigen Edge-Case-Historien kann dies sogar aufgrund von Zusammenführungskonflikten fehlschlagen - trotz der Tatsache, dass Sie auf ein Commit zurückgreifen, das nichts enthält.
Geschichte neu schreiben
Der sauberere Ansatz besteht darin, den Zweig neu zu schreiben. Im Gegensatz zu mit git rebase
müssen Sie nachschlagen, von welchem Commit Ihre Niederlassung ausgeht:
git replace <currentroot> --graft newroot
git filter-branch master
Das Umschreiben erfolgt natürlich im zweiten Schritt; Es ist der erste Schritt, der einer Erklärung bedarf. Was git replace
tut , ist es Git sagt , dass , wenn es einen Verweis auf ein Objekt sieht man ersetzt wollen, Git statt auf dem Ersatz des Objekts aussehen soll.
Mit dem --graft
Schalter sagen Sie etwas anderes als normal. Sie sagen, dass Sie noch kein Ersatzobjekt haben, aber Sie möchten das <currentroot>
Festschreibungsobjekt durch eine exakte Kopie von sich selbst ersetzen , außer dass die übergeordneten Festschreibungen der Ersetzung die von Ihnen aufgelisteten sein sollten (dh die newroot
Festschreibung) ). Anschließend git replace
wird dieses Commit für Sie erstellt und dieses Commit als Ersatz für Ihr ursprüngliches Commit deklariert.
Wenn Sie nun a ausführen git log
, werden Sie feststellen, dass die Dinge bereits so aussehen, wie Sie es möchten: Der Zweig beginnt bei newroot
.
Beachten Sie jedoch, dass git replace
der Verlauf dadurch weder geändert noch aus Ihrem Repository weitergegeben wird. Es wird lediglich eine lokale Umleitung zu Ihrem Repository von einem Objekt zu einem anderen hinzugefügt. Dies bedeutet, dass niemand sonst die Wirkung dieses Ersatzes sieht - nur Sie.
Deshalb ist der filter-branch
Schritt notwendig. Mit git replace
erstellen Sie eine exakte Kopie mit angepassten übergeordneten Commits für das Root-Commit. git filter-branch
Wiederholt diesen Vorgang dann auch für alle folgenden Commits. Hier wird die Geschichte tatsächlich neu geschrieben, damit Sie sie teilen können.