Git Rebase und Git Push: Nicht schneller Vorlauf, warum verwenden?

68

Ich habe eine Filiale, die anderen Mitwirkenden zur Verfügung stehen sollte und die ständig mit dem Master auf dem Laufenden bleiben sollte.

Leider führt jedes Mal, wenn ich 'git rebase' mache und dann versuche zu pushen, die Meldung 'nicht schnell vorwärts' und die Abtreibung des Pushs. Die einzige Möglichkeit, hier zu pushen, ist die Verwendung von --force. Bedeutet das, dass ich "Git Merge" verwenden sollte, anstatt neu zu gründen, wenn mein Zweig an die Börse ging und andere daran arbeiten?

Snitko
quelle

Antworten:

100

Ein paar Hinweise zur Funktionsweise von Git (nicht technisch):

Wenn Sie die Basis neu festlegen, übernimmt git die fraglichen Commits und "schreibt" sie zusätzlich zu einem sauberen Verlauf erneut fest. Dies soll verhindern, dass der Verlauf angezeigt wird:

Description: tree -> mywork -> merge -> mywork -> merge -> mywork -> merge
Commit SHA1: aaaa -> bbbb   -> cccc  -> dddd   -> eeee  -> ffff   -> gggg

Nach einer Rebase kann es so aussehen (oder ähnlich):

Description: tree -> rebase
Commit SHA1: aaaa -> hhhh

Das Problem ist, dass das neue Commit, das Sie dort veröffentlichen möchten, KEIN Nachkomme ist des Commits an der Spitze des Zweigs .

Jetzt wissen Sie, dass die gleichen Informationen in den Commits enthalten sind, aber git ist dafür verantwortlich, dass diese Commits nicht nur überschrieben werden (bbbb-gggg im obigen Beispiel).


Geteiltes Repo-Modell

Wenn Sie ein freigegebenes Repository verwenden, können solche Dinge sehr verwirrend werden. Lassen Sie mich erklären, warum. Angenommen, ein anderer Entwickler hat den Zweig heruntergezogen, und er hat in seiner Zweigstelle aaaa -> gggg festgeschrieben . Dann machen sie eine Verpflichtung iiii

In der Zwischenzeit haben Sie einen Stoß ausgeführt und einen Stoß erzwungen, wodurch der Baum folgendermaßen aussah:

Description: tree -> rebase
Commit SHA1: aaaa -> hhhh

Wenn der andere Entwickler versucht zu pushen, erhält er eine Meldung "Nicht schneller Vorlauf". Wenn er eine Zusammenführung durchführt, werden beide Historien miteinander verknüpft, und Sie geraten in ein Chaos

So etwas (chaotisch):

Description: tree -> rebase -> mywork -> merge -> mywork -> merge -> mywork -> merge -> devwork -> merge 
Commit SHA1: aaaa -> hhhh   -> bbbb   -> cccc  -> dddd   -> eeee  -> ffff   -> gggg -> iiii    -> jjjj

Mit anderen Worten, wenn andere ziehen UND drücken, ist es besser, dass Sie bis nach dem Rebase beim Git Merge bleiben oder PUSHING vermeiden (und nur Ihre Arbeit neu gründen).


Öffentlich sichtbares Repository-Modell

Vielleicht verwenden Sie ein anderes (gröberes) Modell, bei dem Sie nur möchten, dass die Leute aus Ihrem Repo ziehen können. In diesem Fall ist git push --force nicht schlecht, denn dann können sie damit umgehen. Sie können ihre Änderungen neu begründen , um sie auf Ihre Änderungen zu übertragen, bevor sie Ihnen ihre Patches geben. Es verhindert, dass Ihr Repo durcheinander gerät.

Es kann jedoch einen besseren Weg für Sie geben. Git Push - Spiegel

Von http://www.kernel.org/pub/software/scm/git/docs/git-push.html

Anstatt jede zu pushende Ref zu benennen, wird angegeben, dass alle Refs unter $ GIT_DIR / refs / (einschließlich, aber nicht beschränkt auf refs / Heads /, Refs / Remotes / und Refs / Tags /) in das Remote-Repository gespiegelt werden. Neu erstellte lokale Refs werden an das Remote-Ende verschoben, lokal aktualisierte Refs werden auf dem Remote-Ende zwangsweise aktualisiert und gelöschte Refs werden vom Remote-Ende entfernt. Dies ist die Standardeinstellung, wenn die Konfigurationsoption remote..mirror eingestellt ist.


Eines der großartigen Dinge an Git ist, dass es sehr flexibel ist und viele verschiedene Arten von Workflows ermöglicht. Die wahre Stärke liegt jedoch in der Tatsache, dass es sich um ein verteiltes Modell handelt. Ich glaube, dass der größte ROI erzielt werden kann, wenn es auf diese Weise verwendet wird.

gahooa
quelle
7
Err, eigentlich führt das Zusammenführen zu Zusammenführungs-Commits, die nicht klar geklärt werden müssen. Stattdessen ist es großartig git fetch, git rebase origin/master, alle Ihre lokalen Konflikte mit dem Hauptzweig (zentralisiert) zu lösen und dann reine Commits zu pushen, die nur vorwärts gehen. git pull --rebasehat einen ähnlichen Workflow. Dies ist eine leistungsstarke Option, aber Sie müssen vorsichtig damit sein, da das Zurücksetzen der falschen Dinge Commits umschreiben kann, die sich bereits im Ursprung / Master befinden. ZB andere Zweige nicht neu gründen, es sei denn, sie basieren zuerst auf dem aktuellen Ursprung / Master.
Kzqai
Stimmen Sie zu, Zusammenführungs-Commits sollten vermieden werden, wenn Sie einen Git-Pull ausführen. Ich denke jedoch, dass sie gut zu behalten sind, wenn ein Feature-Zweig absichtlich mit dem Master zusammengeführt wird.
ndbroadbent
3
Ich mag die Erklärung, warum es ein Problem gibt, einen neu basierten Zweig zu pushen. Aber ich bin nicht sicher, was - Spiegel erreicht. Das Lesen der Beschreibung - "gibt an, dass alle Refs gespiegelt werden" - stört mich. Ich möchte nicht, dass alle Refs gespiegelt werden, nur ein Zweig. :) Wird die Benennung eines Zweigs nur diesen widerspiegeln? Es ist mir aus den Git-Dokumenten nicht klar.
John C
2

Nein, Rebase ist bei öffentlichen Repositories völlig legal und kann sogar wünschenswert sein, um die Historie flüssig zu halten. Denken Sie daran, dass Sie Rebase nicht verwenden dürfen, um den Verlauf von remote veröffentlichten Commits neu zu schreiben. Das heißt, Rebase kann nur auf Ihre eigenen lokalen Commits angewendet werden, die Sie noch nie veröffentlicht haben. Sie verwenden Rebase, um Ihre Commits beim Abrufen darüber zu platzieren und sie dann möglicherweise dort anzupassen. Ein weiterer Grund, warum Sie möglicherweise eine solche Nachricht erhalten, ist, dass der Zweig, den Sie pushen, aktualisiert wurde und Sie synchronisieren müssen - holen Sie Ihre Commits ab und setzen Sie sie erneut auf das, was Sie abgerufen haben.

Val
quelle