696 Stimmen

Die ersten beiden Commits in Git zerdrücken?

Con git rebase --interactive <commit> können Sie eine beliebige Anzahl von Übertragungen zu einer einzigen zusammenfassen.

Das ist alles großartig, es sei denn, Sie wollen die Commits in den ersten Commit quetschen. Das scheint unmöglich zu sein.

Gibt es Möglichkeiten, dies zu erreichen?


Mäßig verwandt:

In einer verwandten Frage ist es mir gelungen, einen anderen Ansatz für die Notwendigkeit zu finden, die erste Übergabe zu unterdrücken, nämlich, sie zur zweiten zu machen.

Wenn Sie daran interessiert sind: git: Wie fügt man einen Commit als ersten ein und verschiebt alle anderen?

0 Stimmen

0 Stimmen

Einzeiler: git squash 2 mit dem Alias squash = !"f() { NL=$1; GIT_EDITOR=\"sed -i '2,$NL s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'\"; git rebase -i HEAD~$NL; }; f" . Siehe stackoverflow.com/a/28789349/670229 .

1 Stimmen

Das Skript "squash": Bei zwei Commits existiert der HEAD~2, den dieses Skript erzeugt, nicht, so dass es in diesem einen speziellen Fall nicht funktioniert.

973voto

VonC Punkte 1117238

Update Juli 2012 ( git 1.7.12+ )

Sie können nun alle Commits bis zu Root zurücksetzen und den zweiten Commit auswählen Y mit dem ersten zu zerquetschen X .

git rebase -i --root master

pick sha1 X
squash sha1 Y
pick sha1 Z
git rebase [-i] --root $tip

Dieser Befehl kann nun verwendet werden, um den gesamten Verlauf von " $tip "bis hin zur Root-Übertragung.

Ver commit df5df20c1308f936ea542c86df1e9c6974168472 auf GitHub von Chris Webb ( arachsys ) .

Wie bereits erwähnt in den Kommentaren , a git push --force-with-lease (Sicherer als --force als Mikko Mantalainen uns erinnern ) wäre nach jeder rebase Operation, wenn Sie die Überarbeitung in einem entfernten Repository veröffentlichen müssen.


Originalantwort (Februar 2009)

Ich glaube, Sie finden verschiedene Rezepte dafür in der SO-Frage " Wie kombiniere ich die ersten beiden Commits eines Git-Repositorys? "

Charles Bailey sofern dort die meisten ausführliche Antwort und erinnert uns daran, dass ein Commit ein vollständiger Baum ist (nicht nur die Unterschiede zu einem früheren Zustand).
Und hier haben der alte Commit (der "ursprüngliche Commit") und der neue Commit (das Ergebnis der Zerschlagung) keinen gemeinsamen Vorfahren.
Das heißt, Sie können nicht " commit --amend "die ursprüngliche Übergabe in eine neue Übergabe umwandeln und dann die Historie der vorherigen ursprünglichen Übergabe auf die neue Übergabe umbinden (viele Konflikte)

(Der letzte Satz gilt nicht mehr für git rebase -i --root <aBranch> )

Vielmehr (mit A die ursprüngliche "ursprüngliche Übergabe", und B eine nachfolgende Übertragung musste in die erste eingefügt werden):

  1. Gehen Sie zurück zum letzten Commit, das den ersten Commit bilden soll (HEAD abtrennen):

     git checkout <sha1_for_B>
  2. Setzt den Zweigzeiger auf die ursprüngliche Übergabe zurück, lässt aber den Index und den Arbeitsbaum intakt:

     git reset --soft <sha1_for_A>
  3. Ändern Sie den ursprünglichen Baum mit Hilfe des Baums aus 'B':

     git commit --amend
  4. Markieren Sie vorübergehend diesen neuen ersten Commit (oder merken Sie sich den neuen Commit sha1 manuell):

     git tag tmp
  5. Gehen Sie zurück zum ursprünglichen Zweig (nehmen Sie für dieses Beispiel master an):

     git checkout master
  6. Alle Übertragungen nach B werden auf die neue ursprüngliche Übertragung übertragen:

     git rebase --onto tmp <sha1_for_B>
  7. Entfernen Sie die temporäre Markierung:

     git tag -d tmp

Auf diese Weise wird die " rebase --onto "führt nicht zu Konflikten während des Zusammenführens, da es die Historie neu berechnet gemacht nach die letzte Übertragung ( B ), die in die ursprüngliche (d.h. A ) an tmp (repräsentiert die zerquetschte neue ursprüngliche Übergabe): nur triviale Schnellzusammenführungen.

Das funktioniert für " A-B ", aber auch " A-...-...-...-B "(eine beliebige Anzahl von Übertragungen kann auf diese Weise in die erste Übertragungen gequetscht werden)

2 Stimmen

Toller Tipp. Werde ihn im Hinterkopf behalten. Leider habe ich es mit einem "git svn"-Repos ausprobiert und das hat die Verbindung zum svn unterbrochen. Keine Sorge, ich hatte ein Backup...

0 Stimmen

Das funktioniert bei mir nicht. Wenn ich dann weitermache mit git push erhalte ich eine Fehlermeldung, die besagt, ich müsse git pull Erstens. Wenn ich das tue und dann drücke, lande ich Wiederholung mehrere der Übertragungen anstelle von Reduzierung die Anzahl der Übertragungen.

1 Stimmen

@MattHuggins, aber wenn Sie umbasen, müssen Sie dann schieben --zwingen, Sie können nicht einfach schieben. Der Verlauf wurde geändert (anderer SHA1), so dass der Push nicht mehr im Schnelldurchlauf erfolgt. Ich bestätige, dass, wenn Sie ziehen, dann schieben, Sie am Ende mit doppelten Übertragungen. Siehe stackoverflow.com/q/7462553/6309

36voto

Mike Looijmans Punkte 319

Wenn Sie einfach alle Commits in einen einzigen, ersten Commit zusammenfassen wollen, setzen Sie das Repository zurück und ändern den ersten Commit:

git reset hash-of-first-commit
git add -A
git commit --amend

Beim Zurücksetzen von Git bleibt der Arbeitsbaum intakt, d.h. alles ist noch vorhanden. Fügen Sie also die Dateien mit dem Befehl git add hinzu und ändern Sie den ersten Commit mit diesen Änderungen. Im Vergleich zu rebase -i verlieren Sie allerdings die Möglichkeit, die Git-Kommentare zusammenzuführen.

33voto

fonsinchen Punkte 321

Ich habe das Skript von VonC so überarbeitet, dass es alles automatisch macht und mich nicht mehr fragt. Man gibt ihm zwei SHA1-Commits und es wird alles, was dazwischen liegt, in einen Commit mit dem Namen "squashed history" zerquetschen:

#!/bin/sh
# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout $2

# reset the branch pointer to the initial commit (= $1),
# but leaving the index and working tree intact.
git reset --soft $1

# amend the initial tree using the tree from $2
git commit --amend -m "squashed history"

# remember the new commit sha1
TARGET=`git rev-list HEAD --max-count=1`

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after $2 onto the new initial commit
git rebase --onto $TARGET $2

0 Stimmen

+1 für die Erstellung. Sie sollten erwähnen, dachte, dass es nicht für das Umbasieren von Commits irgendwo in der Geschichte funktioniert, nur aktuelle Commits.

0 Stimmen

Siehe auch diese Antwort .

23voto

Ryan C. Thompson Punkte 38726

Ich vermeide dieses Problem, indem ich immer eine "no-op"-Erstübergabe durchführe, bei der das einzige im Repository eine leere .gitignore-Datei ist:

https://github.com/DarwinAwardWinner/git-custom-commands/blob/master/bin/git-myinit

Auf diese Weise gibt es keinen Grund, an der ersten Übergabe herumzupfuschen.

4 Stimmen

Git sollte dies automatisch tun, wenn es weniger verrückt wäre. Es gibt eine nette Möglichkeit, einen solchen initialen Commit in ein bestehendes Repo einzufügen... stackoverflow.com/questions/645450/

1 Stimmen

git commit --allow-empty -m empty ist oft mein erster Commit. Das vermeidet sogar die "Verschmutzung" des Commits mit einer .gitignore Datei. Bitte beachten Sie, dass einige ältere Tools Probleme hatten, leere Bäume wie diesen anzuzeigen.

5voto

Antony Hatchkins Punkte 28362

Dadurch wird die zweite Übergabe mit der ersten zusammengelegt:

A-B-C-... -> AB-C-...

git filter-branch --commit-filter '
    if [ "$GIT_COMMIT" = <sha1ofA> ];
    then
        skip_commit "$@";
    else
        git commit-tree "$@";
    fi
' HEAD

Die Verpflichtungserklärung für AB wird von B übernommen (obwohl ich A vorziehen würde).

Hat den gleichen Effekt wie die Antwort von Uwe Kleine-König, funktioniert aber auch bei nicht-initialem A.

0 Stimmen

@Anothony - Hallo, als Git-Anfänger bin ich mir nicht sicher, ob dies meinen Bedürfnissen entspricht, aber es sieht vielversprechend aus. Könnten Sie vielleicht ein wenig mehr erklären? Ich versuche, alle meine Git-Commits in einem einzigen zusammenzufassen, um sie in ein bestehendes Projekt zu integrieren (der ursprüngliche Commit bleibt bestehen). Da ich jedoch viele Projekte habe, benötige ich ein Skript, und git rebase -i ist nicht geeignet. Wird dieser Befehl für mich funktionieren? Gebe ich den Hash für die erste Übertragung (A) an, wobei C HEAD ist? Jede weitere Erklärung, die Sie anbieten könnten, wäre großartig! Vielen Dank!

0 Stimmen

Das Zusammenfassen aller Übertragungen in eine einzige ist im Allgemeinen nicht erforderlich, wenn zwei Projekte zusammengeführt werden. Erklären Sie in einer separaten Frage, warum Sie es brauchen. "Wie gebe ich den Hash für den ersten Commit(A) an, wobei C HEAD ist?" ist ebenfalls eine separate Frage. git rev-list --reverse HEAD|head -n1 könnte die Antwort sein

CodeJaeger.com

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.

Powered by:

X