Wie drückst du dein gesamtes Repository auf den ersten Commit zusammen?
Ich kann zum ersten Commit neu basieren, aber dann hätte ich 2 Commits. Gibt es eine Möglichkeit, auf den Commit vor dem ersten zu verweisen?
Wie drückst du dein gesamtes Repository auf den ersten Commit zusammen?
Ich kann zum ersten Commit neu basieren, aber dann hätte ich 2 Commits. Gibt es eine Möglichkeit, auf den Commit vor dem ersten zu verweisen?
Ab git 1.6.2 können Sie git rebase --root -i
verwenden.
Ändern Sie für jeden Commit außer dem ersten pick
in squash
im Editor, der erscheint.
Diese Antwort ist ok, aber wenn Sie interaktiv mehr als, sagen wir, 20 Commits neu basieren, wird das interaktive Rebasieren wahrscheinlich viel zu langsam und unhandlich sein. Sie dürften Schwierigkeiten haben, Hunderte oder Tausende von Commits zu squaschen. In diesem Fall würde ich einen soft oder mixed Reset zum Root-Commit durchführen und dann erneut committen.
Dies war der einzige Weg, wie ich einen Master-Zweig zu meinem neu erstellten GitHub-Repository hinzufügen konnte, nachdem ich einen Feature-Zweig gepusht hatte, für den ich einen Pull-Request erstellen wollte.
Sie können einen squash-all commit direkt von HEAD
aus erstellen, ohne jegliches Rebase, führen Sie einfach aus:
git reset $(git commit-tree HEAD^{tree} -m "Ein neuer Anfang")
Hinweis: Dies erfordert eine POSIX-kompatible Shell wie bash/zsh oder Git Bash unter Windows.
~/.gitconfig
[alias]
squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} \"$@\");};f"
Dann führen Sie einfach aus: git squash-all -m "ein ganz neuer Anfang"
Hinweis: Geben Sie entweder die Commit-Nachricht über standardmäßige Eingabe oder über die Optionen -m
/-F
an, genau wie beim git commit Befehl. Siehe git-commit-tree Anleitung.
Alternativ können Sie das Alias mit dem folgenden Befehl erstellen:
git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} "$@");};f'
Erstellen eines einzelnen Commits über git commit-tree
Was git commit-tree HEAD^{tree} -m "Ein neuer Anfang"
macht ist:
Erstellt ein neues Commit-Objekt auf Basis des bereitgestellten Tree-Objekts und gibt die ID des neuen Commits auf der Standardausgabe aus. Die Protokollnachricht wird von der Standardmäßigen Eingabe gelesen, es sei denn, die Optionen -m oder -F werden angegeben.
Der Ausdruck HEAD^{tree}
repräsentiert das Tree-Objekt, das zu HEAD
gehört, nämlich die Spitze Ihres aktuellen Branches. Siehe Tree-Objekte und Commit-Objekte.
Zurücksetzen des aktuellen Branches auf das neue Commit
Dann setzt git reset
einfach den aktuellen Branch auf das neu erstellte Commit-Objekt zurück.
Auf diese Weise wird nichts im Arbeitsbereich geändert, und es ist kein Rebase/Squash erforderlich, was es wirklich schnell macht. Und die benötigte Zeit ist unabhängig von der Repositorygröße oder der Geschichte.
Dies ist nützlich, um den "initial commit" in einem neuen Projekt mithilfe eines anderen Repositories als Vorlage/Archetyp/Saat/Gerüst zu erstellen. Zum Beispiel:
cd mein-neues-projekt
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "Initialer Commit")
Dies umgeht das Hinzufügen des Vorlagen-Repositorys als Remote (origin
oder anders) und kollabiert die Geschichte des Vorlagen-Repositorys in Ihren initialen Commit.
Die Git-Revisions-Syntax (HEAD^{tree}) Syntax wird hier erklärt, falls sich jemand anderes gefragt hat: jk.gs/gitrevisions.html
@ColinBowern, danke für den Hinweis, ich habe die Antwort mit etwas Informationen zur Baumobjektsyntax aktualisiert und einen Verweis aus dem Git-Buch hinzugefügt.
Wird dadurch sowohl das lokale als auch das entfernte Repository zurückgesetzt oder nur eines von beiden?
Wenn Sie alle Ihre Commits nur bis zum Stammcommit zusammenführen möchten, dann während
git rebase --interaktiv --root
funktionieren kann, ist es für eine große Anzahl von Commits (zum Beispiel Hunderte von Commits) unpraktisch, weil die Rebase-Operation wahrscheinlich sehr langsam ausgeführt wird, um die interaktive Rebase-Editor-Commit-Liste zu generieren und den Rebase selbst auszuführen.
Hier sind zwei schnellere und effizientere Lösungen, wenn Sie eine große Anzahl von Commits zusammenführen:
Sie können einfach einen neuen Waisen-Branch an der Spitze (d.h. dem neuesten Commit) Ihres aktuellen Branches erstellen. Dieser Waisen-Branch bildet den initialen Stammcommit eines völlig neuen und separaten Commit-Verlaufbaums, der effektiv äquivalent zur Zusammenführung aller Ihrer Commits ist:
git checkout --orphan neuer-master master
git commit -m "Geben Sie die Commit-Nachricht für Ihren neuen initialen Commit ein"
# Überschreiben Sie den alten Master-Branch-Verweis mit dem neuen
git branch -M neuer-master master
Dokumentation:
Eine weitere effiziente Lösung besteht darin, einfach einen gemischten oder soft reset auf den Stammcommit zu verwenden:
git branch vorReset
git reset --soft
git commit --amend
# Überprüfen Sie, dass der neue bearbeitete Stamm nicht vom vorherigen Branch-Zustand abweicht
git diff vorReset
Dokumentation:
Alternative Lösung #1 FTW. Nur um es hinzuzufügen, wenn Sie Ihre Änderungen auf den Remote pushen möchten, tun Sie git push origin master --force
.
Vielleicht ist der einfachste Weg, einfach ein neues Repository mit dem aktuellen Stand der Arbeitskopie zu erstellen. Wenn Sie alle Commit-Messages behalten möchten, könnten Sie zuerst git log > original.log
ausführen und dann diese für Ihre initiale Commit-Nachricht im neuen Repository editieren:
rm -rf .git
git init
git add .
git commit
oder
git log > original.log
# editiere original.log wie gewünscht
rm -rf .git
git init
git add .
git commit -F original.log
@OlivierRefalo - Es gibt keine Möglichkeit, Zweige zu bewahren, während die gesamte Historie auf einen einzigen Commit reduziert wird (einen neuen initialen Commit erstellen). Wenn jemand Zweige erhalten möchte, muss er den alten initialen Commit aufbewahren. Um das zu tun, rebase gegen den initialen Commit (wie in der Frage beschrieben) und behalten Sie möglicherweise bis zu zwei Commits.
Eigentlich gibt es einen Weg, um Zweige zu erhalten, siehe Antwort von @FrefichRaabe. Allerdings klingt das Konzept alter Zweige mit einer Geschichte, die auf einen einzigen Commit reduziert wurde, seltsam.
echo "Nachricht" | git commit-tree HEAD^{tree}
Dies erstellt einen verwaisten Commit mit dem Baum von HEAD und gibt dessen Namen (SHA-1) auf stdout aus. Setzen Sie dann einfach Ihren Branch dort zurück.
git reset SHA-1
Um das obige in einem Schritt auszuführen:
git reset $(git commit-tree HEAD^{tree} -m "Erster Commit.")
^ DAS! - sollte eine Antwort sein. Nicht ganz sicher, ob es die Absicht des Autors war, aber es war meine (benötigt ein sauberes Repository mit nur einem Commit, und das erledigt den Job).
@ryenus, deine Lösung hat genau das getan, wonach ich gesucht habe. Wenn du deinen Kommentar als Antwort hinzufügst, werde ich ihn akzeptieren.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
43 Stimmen
@innaM - Es ist der ursprüngliche Commit, der den Git hervorgebracht hat. (Hofft, dass der Humor gut genug durch das Internet übertragen wird).
14 Stimmen
Für diejenigen, die später zu dieser Frage kommen, achten Sie darauf, die modernere Antwort zu verwenden.
1 Stimmen
Verwandt, aber kein Duplikat (
--root
ist tatsächlich nicht die beste Lösung zum Zusammenfassen aller Commits, wenn es viele davon gibt, die zusammengefasst werden müssen): Kombinieren der ersten beiden Commits eines Git-Repositorys?.1 Stimmen
^ diese moderne Antwort ist nicht die beste, bessere Lösung ohne Overhead ist stackoverflow.com/questions/1657017#23486788
2 Stimmen
Imo: das ist das Beste von @MrTux: stackoverflow.com/questions/30236694/….
0 Stimmen
Möglicher Duplikat von Die ersten beiden Commits eines Git-Repository zusammenführen?
1 Stimmen
Ich weiß, die Frage verlangt eine schnelle Lösung, aber man könnte auch: ´rm -rf .git´ und ´git commit -m"neue Nachricht"´.