web-dev-qa-db-de.com

Wie man alle git Commits in einem zerquetscht?

Wie können Sie Ihr gesamtes Repository bis zum ersten Commit komprimieren?

Ich kann auf das erste Commit zurückgreifen, aber das würde mich mit 2 Commits belassen. Gibt es eine Möglichkeit, auf das Commit vor dem ersten zu verweisen?

408
Verhogen

Am einfachsten ist es vielleicht, ein neues Repository mit dem aktuellen Status der Arbeitskopie zu erstellen. Wenn Sie alle Commit-Nachrichten behalten möchten, können Sie zuerst git log > original.log und bearbeiten Sie das für Ihre erste Festschreibungsnachricht im neuen Repository:

rm -rf .git
git init
git add .
git commit

oder

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log
124
Pat Notz

In neueren Versionen von Git können Sie git rebase --root -i.

Ändern Sie für jedes Commit außer dem ersten pick in squash.

591
Jordan Lewis

Aktualisieren

Ich habe einen Alias ​​git squash-all Erstellt.
Verwendungsbeispiel : git squash-all "a brand new start".

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"

Vorsichtsmaßnahme : Denken Sie daran, einen Kommentar anzugeben, da sonst die Standard-Festschreibungsmeldung "Ein Neustart" verwendet wird.

Oder Sie können den Alias ​​mit dem folgenden Befehl erstellen:

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'

Einzeiler

git reset $(git commit-tree HEAD^{tree} -m "A new start")

Hinweis : Hier ist "A new start" Nur ein Beispiel. Sie können auch Ihre eigene Sprache verwenden.

TL; DR

Keine Notwendigkeit zu quetschen, verwenden Sie git commit-tree, Um ein Orphan-Commit zu erstellen und gehen Sie damit um.

Erklären

  1. erstelle ein einzelnes Commit über git commit-tree

    Was git commit-tree HEAD^{tree} -m "A new start" Macht, ist:

    Erstellt ein neues Festschreibungsobjekt basierend auf dem bereitgestellten Baumobjekt und gibt die neue Festschreibungsobjekt-ID auf stdout aus. Die Protokollnachricht wird von der Standardeingabe gelesen, sofern nicht die Optionen -m oder -F angegeben sind.

    Der Ausdruck HEAD^{tree} Bedeutet das Baumobjekt, das HEAD entspricht, nämlich die Spitze Ihres aktuellen Zweigs. siehe Tree-Objects und Commit-Objects .

  2. setzen Sie den aktuellen Zweig auf das neue Festschreiben zurück

    Dann setzt git reset Einfach den aktuellen Zweig auf das neu erstellte Festschreibungsobjekt zurück.

Auf diese Weise wird nichts im Arbeitsbereich berührt, und es ist auch kein Rebase/Squash erforderlich, wodurch es sehr schnell geht. Die benötigte Zeit spielt für die Größe des Repositorys oder die Verlaufstiefe keine Rolle.

Variante: Neues Repo aus einer Projektvorlage

Dies ist nützlich, um das "Initial Commit" in einem neuen Projekt unter Verwendung eines anderen Repositorys als Vorlage/Archetyp/Seed/Skeleton zu erstellen. Zum Beispiel:

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")

Dies vermeidet das Hinzufügen des Vorlagen-Repos als Remote (Origin oder auf andere Weise) und reduziert den Verlauf des Vorlagen-Repos in Ihrem ursprünglichen Commit.

272
ryenus

Wenn Sie nur alle Commits auf das Root-Commit reduzieren möchten, müssen Sie while ausführen

git rebase --interactive --root

dies ist für eine große Anzahl von Commits (z. B. Hunderte von Commits) unpraktisch, da der Rebase-Vorgang wahrscheinlich sehr langsam ausgeführt wird, um die interaktive Commit-Liste des Rebase-Editors zu generieren, und auch für die Rebase selbst.

Hier sind zwei schnellere und effizientere Lösungen, wenn Sie eine große Anzahl von Commits quetschen:

Alternative Lösung 1: Orphan Branches

Sie können einfach einen neuen Orphan-Zweig an der Spitze (d. H. Dem letzten Festschreiben) Ihres aktuellen Zweigs erstellen. Dieser Orphan-Zweig bildet das ursprüngliche Root-Commit eines völlig neuen und separaten Commit-Verlaufsbaums, der praktisch dem Zerquetschen aller Commits entspricht:

git checkout --Orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master

Dokumentation:

Alternative Lösung Nr. 2: Soft Reset

Eine andere effiziente Lösung besteht darin, einfach einen gemischten oder einen Soft-Reset für das Root-Commit <root> Durchzuführen:

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset

Dokumentation:

152
user456814
echo "message" | git commit-tree HEAD^{tree}

Dadurch wird ein verwaistes Commit mit dem HEAD-Baum erstellt und dessen Name (SHA-1) auf stdout ausgegeben. Dann setzen Sie dort einfach Ihre Filiale zurück.

git reset SHA-1
47
kusma

Hier ist, wie ich dazu kam, für den Fall, dass es für jemand anderen funktioniert:

Denken Sie daran, dass dies immer mit einem Risiko verbunden ist und es niemals eine schlechte Idee ist, einen sicheren Zweig zu erstellen, bevor Sie beginnen.

Beginnen Sie mit der Protokollierung

git log --oneline

Scrollen Sie zum ersten Festschreiben und kopieren Sie SHA

git reset --soft <#sha#>

Ersetzen Sie <#sha#> W/the SHA aus dem Protokoll kopiert

git status

Stellen Sie sicher, dass alles grün ist, andernfalls führen Sie git add -A Aus.

git commit --amend

Alle aktuellen Änderungen an der aktuellen ersten Übergabe ändern

Drücken Sie nun diesen Zweig und es wird überschrieben, was da ist.

37
Logan

Am einfachsten ist es, den aktuellen Zweig mit dem Befehl 'plumbing' update-ref Zu löschen.

Sie können git branch -D Nicht verwenden, da es ein Sicherheitsventil hat, das das Löschen des aktuellen Zweigs verhindert.

Dies versetzt Sie wieder in den Status 'Initial Commit', in dem Sie mit einem neuen Initial Commit beginnen können.

git update-ref -d refs/heads/master
git commit -m "New initial commit"
32
CB Bailey

Ich habe etwas über die Verwendung von Transplantaten gelesen, aber nie viel nachgeforscht.

Wie auch immer, Sie können die letzten 2 Commits manuell mit etwas wie folgendem quetschen:

git reset HEAD~1
git add -A
git commit --amend
30

Zerquetschen Sie zunächst alle Commits mit git rebase --interactive Zu einem einzigen Commit. Jetzt müssen Sie nur noch zwei Aufgaben ausführen. Lesen Sie dazu eines von

16
Frerich Raabe

In einer Zeile von 6 Wörtern

git checkout --Orphan new_root_branch  &&  git commit
12
kyb

Mit Transplantaten zerdrücken

Datei hinzufügen .git/info/grafts, lege dort den Commit-Hash ab, der deine Wurzel sein soll

git log wird nun mit diesem Commit beginnen

Um es "real" zu machen, starte git filter-branch

4
dimus

erstellen Sie ein Backup

git branch backup

zurücksetzen auf angegebenen Commit

git reset --soft <#root>

fügen Sie dann alle Dateien zum Staging hinzu

git add .

festschreiben, ohne die Nachricht zu aktualisieren

git commit --amend --no-edit

Schieben Sie einen neuen Zweig mit gequetschten Commits zum Repo

git Push -f
3
David

Diese Antwort ist besser als die obige Antwort (bitte stimmen Sie ab), vorausgesetzt, dass Sie nicht nur ein Commit erstellen (keine Eltern, keine Historie), sondern auch auch alle Commit-Daten beibehalten möchten davon verpflichten:

  • Autor (Name und E-Mail)
  • Erstelldatum
  • Commiter (Name und E-Mail)
  • Festgeschriebenes Datum
  • Protokollnachricht festschreiben

Natürlich wird sich das Commit-SHA des neuen/einzelnen Commits ändern, da es eine neue (Nicht-) Historie darstellt und zu einem parentless/root-Commit wird.

Dies kann durch Lesen von git log Und Setzen einiger Variablen für git commit-tree Erreicht werden. Angenommen, Sie möchten ein einzelnes Commit aus master in einem neuen Zweig erstellen one-commit Und dabei die obigen Commit-Daten beibehalten:

git checkout -b one-commit master ## create new branch to reset
git reset --hard \
$(eval "$(git log master -n1 --format='\
COMMIT_MESSAGE="%B" \
GIT_AUTHOR_NAME="%an" \
GIT_AUTHOR_EMAIL="%ae" \
GIT_AUTHOR_DATE="%ad" \
GIT_COMMITTER_NAME="%cn" \
GIT_COMMITTER_EMAIL="%ce" \
GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <<COMMITMESSAGE
$COMMIT_MESSAGE
COMMITMESSAGE
')
1
javabrett

Normalerweise mache ich das so:

  • Stellen Sie sicher, dass alles festgeschrieben ist, und notieren Sie sich die neueste Festschreibungs-ID, falls etwas schief geht, oder erstellen Sie einen separaten Zweig als Sicherung

  • Lauf git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD`, um Ihren Kopf auf das erste Commit zurückzusetzen, aber Ihren Index unverändert zu lassen. Alle Änderungen seit dem ersten Festschreiben werden nun als festschreibungsbereit angezeigt.

  • Lauf git commit --amend -m "initial commit" Um Ihr Commit auf das erste Commit zu ändern und die Commit-Nachricht zu ändern, oder um die vorhandene Commit-Nachricht beizubehalten, können Sie git commit --amend --no-edit

  • Lauf git Push -f, um Änderungen zu erzwingen