Die ersten beiden Commits eines Git-Repositorys kombinieren?

197

Angenommen, Sie haben eine Historie mit den drei Commits A, B und C :

A-B-C

Ich möchte die beiden Commits A und B zu einem Commit AB kombinieren :

AB-C

Ich habe es versucht

git rebase -i A

Das öffnet meinen Editor mit folgenden Inhalten:

pick e97a17b B
pick asd314f C

Ich ändere das auf

squash e97a17b B
pick asd314f C

Dann sagt Git 1.6.0.4:

Cannot 'squash' without a previous commit

Gibt es einen Weg oder ist das einfach unmöglich?

Christian
quelle

Antworten:

168

Verwendung git rebase -i --root ab Git Version 1.7.12 .

Ändern Sie in der interaktiven Rebase-Datei die zweite Zeile von Commit B in Squash und lassen Sie die anderen Zeilen bei Auswahl :

pick f4202da A
squash bea708e B
pick a8c6abc C

Dadurch werden die beiden Commits A und B zu einem Commit AB kombiniert .

Gefunden in dieser Antwort .

kostmo
quelle
126

Du versuchtest:

git rebase -i A

Es ist möglich, so zu beginnen, wenn Sie fortfahren editanstatt squash:

edit e97a17b B
pick asd314f C

dann renne

git reset --soft HEAD^
git commit --amend
git rebase --continue

Getan.

David Lichteblau
quelle
4
Wenn Sie dies tun, um einen Github-Kern leise zu beheben, müssen Sie dem Commit -m "initial" hinzufügen. ;-)
Bruno Bronosky
1
git rebase --abortvon vorne anfangen und es richtig machen (nicht das erste Commit im Editor quetschen)
oma
66

Awar das anfängliche Festschreiben, aber jetzt möchten Sie Bdas anfängliche Festschreiben sein. Git-Commits sind ganze Bäume, keine Unterschiede, selbst wenn sie normalerweise anhand des von ihnen eingeführten Unterschieds beschrieben und betrachtet werden.

Dieses Rezept funktioniert auch dann, wenn zwischen A und B sowie zwischen B und C mehrere Commits bestehen.

# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout <sha1_for_B>

# reset the branch pointer to the initial commit,
# but leaving the index and working tree intact.
git reset --soft <sha1_for_A>

# amend the initial tree using the tree from 'B'
git commit --amend

# temporarily tag this new initial commit
# (or you could remember the new commit sha1 manually)
git tag tmp

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

# Replay all the commits after B onto the new initial commit
git rebase --onto tmp <sha1_for_B>

# remove the temporary tag
git tag -d tmp
CB Bailey
quelle
1
Dies löst eine massive interaktive Rebase aus, wenn ich das machegit rebase --onto tmp <sha1_for_B>
Alex
In Anbetracht der Tatsache, dass ich ein brandneues Repo mit nur zwei Commits hatte (das ich zu einem zusammenfassen wollte), funktionierte dies perfekt für mich. Vielen Dank @CB Bailey
RominRonin
10

Im Fall einer interaktiven Rebase müssen Sie dies vor A tun, damit die Liste wie folgt lautet:

pick A
pick B
pick C

werden:

pick A
squash B
pick C

Wenn A das anfängliche Commit ist, müssen Sie ein anderes anfängliches Commit haben, bevor A. Git an Unterschiede denkt. Es wird den Unterschied zwischen (A und B) und (B und C) bearbeiten. Daher funktioniert der Kürbis in Ihrem Beispiel nicht.

Loki
quelle
9

Für den Fall, dass Sie Hunderte oder Tausende von Commits haben, verwenden Sie die Antwort von kostmo von

git rebase -i --root

Dies kann unpraktisch und langsam sein, nur aufgrund der großen Anzahl von Commits, die das Rebase-Skript zweimal verarbeiten muss , einmal, um die interaktive Rebase-Editorliste zu erstellen (in der Sie auswählen, welche Aktion für jedes Commit ausgeführt werden soll) und einmal, um das Commit tatsächlich auszuführen erneute Anwendung von Commits.

Hier ist eine alternative Lösung , mit der Sie die Zeitkosten für die Erstellung der Liste der interaktiven Rebase-Editoren vermeiden können, indem Sie überhaupt keine interaktive Rebase verwenden . Auf diese Weise ähnelt es der Lösung von Charles Bailey . Sie erstellen einfach einen verwaisten Zweig aus dem zweiten Commit und setzen dann alle darüber liegenden Commits neu fest:

git checkout --orphan orphan <second-commit-sha>
git commit -m "Enter a commit message for the new root commit"
git rebase --onto orphan <second-commit-sha> master

Dokumentation

Gemeinschaft
quelle
1

In einer verwandten Frage gelang es mir, einen anderen Ansatz für die Notwendigkeit zu finden, gegen das erste Commit zu quetschen, nämlich es zum zweiten zu machen.

Wenn Sie interessiert sind: git: Wie füge ich ein Commit als erstes ein und verschiebe alle anderen?

kch
quelle
Wäre es besser, wenn die Antwort auch hier wiederholt würde? Ich bin mir nicht sicher.
0

Git-Befehl für Squad: Git Rebase -i HEAD ~ [Anzahl der Commits]

Nehmen wir an, Sie haben unten einen Git-Commit-Verlauf:


pick 5152061 feat: Unterstützung für das Speichern von Bildern hinzugefügt. (A)
Wählen Sie 39c5a04 Fix: Fehlerbehebungen. (B)
839c6b3 Fix auswählen: Konflikt gelöst. (C)

Nun möchten Sie A und B zu AB quetschen. Führen Sie die folgenden Schritte aus:


pick 5152061 feat: Unterstützung für das Speichern von Bildern hinzugefügt. (A)
s 39c5a04 Fix: Fehlerbehebungen. (B)
839c6b3 Fix auswählen: Konflikt gelöst. (C)

Hinweis: Für das Squashing-Commit können wir Squash oder s verwenden. Das Endergebnis ist:
pick 5152061 feat: Unterstützung für das Speichern von Bildern hinzugefügt. (AB)
Auswahl 839c6b3 Fix: Konflikt gelöst. (C)

Sumit
quelle
-1

Sie müssen ein bisschen Befehlszeilenmagie ausführen.

git checkout -b a A
git checkout B <files>
git commit --amend
git checkout master
git rebase a

Damit sollten Sie einen Zweig haben, der AB und C als Commits hat.

Bombe
quelle
Da die alten und neuen anfänglichen Commits keinen gemeinsamen Vorfahren haben, kann es zu unnötigen Konflikten kommen, wenn git versucht, die gesamte Historie des Masters auf a anzuwenden, obwohl sie einen gemeinsamen Baum haben. Mit der Option --onto zum Git-Rebase können Sie Git den richtigen Ort für den Beginn der Anwendung mitteilen.
CB Bailey