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?



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 .


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.


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

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.


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



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)


-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.


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.