it-swarm.com.de

Git Merge mit Force Overwrite

Ich habe einen Zweig namens demo, den ich mit dem Zweig master zusammenführen muss. Mit folgenden Befehlen kann ich das gewünschte Ergebnis erzielen:

git pull Origin demo
git checkout master
git pull Origin master
git merge demo
git Push Origin master

Meine einzige Sorge ist, wenn es irgendwelche Zusammenführungsprobleme gibt, ich möchte git anweisen, Änderungen in der master-Verzweigung zu überschreiben, ohne mir die Aufforderung zum Zusammenführen zu geben. Änderungen im Zweig demo sollten daher Änderungen im Zweig master automatisch überschreiben.

Ich habe mich umgesehen, dass es mehrere Optionen gibt, aber ich möchte kein Risiko beim Zusammenführen eingehen.

62
OpenStack

Nicht wirklich mit dieser Antwort verwandt, aber ich würde git pull Fallen lassen, das nur git fetch Gefolgt von git merge Ausführt. Sie führen drei Zusammenführungen durch, wodurch Ihr Git drei Abrufvorgänge ausführt, wenn Sie nur einen Abruf benötigen. Daher:

git fetch Origin   # update all our Origin/* remote-tracking branches

git checkout demo         # if needed -- your example assumes you're on it
git merge Origin/demo     # if needed -- see below

git checkout master
git merge Origin/master

git merge -X theirs demo   # but see below

git Push Origin master     # again, see below

Kontrolle über die schwierigste Verschmelzung

Der interessanteste Teil hier ist git merge -X theirs. Als root545 notiert werden die Optionen -X An die Zusammenführungsstrategie und sowohl die Standardstrategie recursive als auch die Alternativstrategie resolve übergeben nimm -X ours oder -X theirs (das eine oder andere, aber nicht beide). Um zu verstehen, was sie tun, müssen Sie wissen, wie Git Konflikte findet und behandelt .

In einigen Dateien kann ein Zusammenführungskonflikt auftreten1 wenn sich die Basisversion von der aktuellen Version (auch als lokal, HEAD oder --ours bezeichnet) unterscheidet und die andere (auch remote oder --theirs genannte) Version derselben Datei. Das heißt, der Zusammenschluss hat drei Revisionen (drei Commits) identifiziert: base, our und their. Die "Basis" -Version ist von der Merge-Basis zwischen unserem Commit und ihrem Commit, wie im Commit-Diagramm zu sehen (mehr dazu in anderen StackOverflow-Beiträgen). Git hat dann zwei Arten von Änderungen gefunden: "Was wir getan haben" und "Was sie getan haben". Diese Änderungen werden (im Allgemeinen) zeilenweise auf rein textueller Basis vorgenommen. Git hat kein wirkliches Verständnis für den Inhalt von Dateien. es wird lediglich jede Textzeile verglichen.

Diese Änderungen werden in der Ausgabe von git diff Angezeigt und haben wie immer auch den Kontext . Es ist möglich, dass Dinge, die wir geändert haben, sich in einer anderen Zeile befinden als Dinge, die sie geändert haben, so dass die Änderungen nicht kollidieren, sondern sich auch der Kontext geändert hat (z. B. weil sich unsere Änderung am oberen oder unteren Rand der Datei befindet, Damit die Datei in unserer Version nicht mehr angezeigt wird, haben sie oben oder unten mehr Text hinzugefügt.

Wenn die Änderungen in verschiedenen Zeilen vorkommen, ändern wir beispielsweise color in colour in Zeile 17 und sie ändern fred bis barney in Zeile 71 - dann liegt kein Konflikt vor: Git nimmt einfach beide Änderungen an. Wenn die Änderungen in denselben Zeilen erfolgen, aber identische Änderungen sind, nimmt Git eine Kopie der Änderung. Nur wenn sich die Änderungen in derselben Zeile befinden, sich jedoch in unterschiedlichen Änderungen befinden oder wenn es sich um einen Sonderfall handelt, bei dem der Kontext gestört wird, tritt ein Konflikt zwischen Ändern und Ändern auf.

Die Optionen -X ours Und -X theirs Teilen Git mit, wie dieser Konflikt gelöst werden kann, indem nur eine der beiden Änderungen ausgewählt wird: unsere oder ihre. Da Sie sagten, Sie mischen demo (ihre) mit master (unsere) und möchten die Änderungen von demo, möchten Sie -X theirs.

Das blinde Anwenden von -X Ist jedoch gefährlich. Nur weil unsere Änderungen nicht Zeile für Zeile in Konflikt standen, heißt das nicht, dass unsere Änderungen tatsächlich nicht in Konflikt standen! Ein klassisches Beispiel findet sich in Sprachen mit Variablendeklarationen. Die Basisversion deklariert möglicherweise eine nicht verwendete Variable:

int i;

In unserer Version löschen wir die nicht verwendete Variable, damit eine Compiler-Warnung verschwindet. In ihrer Version fügen sie einige Zeilen später eine Schleife hinzu und verwenden dabei i. als Schleifenzähler. Wenn wir die beiden Änderungen kombinieren, wird der resultierende Code nicht mehr kompiliert. Die Option -X Ist hier keine Hilfe, da sich die Änderungen in verschiedenen Zeilen befinden.

Wenn Sie über eine automatisierte Testsuite verfügen, ist es am wichtigsten, die Tests nach dem Zusammenführen auszuführen. Sie können dies nach dem Festschreiben tun und die Probleme bei Bedarf später beheben. oder Sie können dies vor dem Festschreiben tun, indem Sie --no-commit zum Befehl git merge hinzufügen. Die Details dazu überlassen wir anderen Beiträgen.


1Sie können auch Konflikte in Bezug auf "dateiweite" Vorgänge bekommen, z. B. wenn wir die Schreibweise eines Wortes in einer Datei korrigieren (damit wir eine Änderung haben) und sie löschen die gesamte Datei (damit sie einen Löschvorgang haben). Git wird diese Konflikte unabhängig von -X - Argumenten nicht alleine lösen.


Weniger Zusammenführungen und/oder intelligentere Zusammenführungen und/oder Rebase

Es gibt drei Zusammenführungen in unseren beiden Befehlssequenzen. Das erste ist, Origin/demo In das lokale demo zu bringen (Ihr verwendet git pull, Das, wenn Ihr Git sehr alt ist, Origin/demo Aber nicht aktualisieren kann wird das gleiche Endergebnis erzeugen). Die zweite ist, Origin/master In master zu bringen.

Mir ist nicht klar, wer demo und/oder master aktualisiert. Wenn Sie Ihren eigenen Code in Ihrem eigenen demo-Zweig schreiben, schreiben und andere Code und verschieben ihn in den demo-Zweig in Origin, dann kann diese Zusammenführung im ersten Schritt Konflikte verursachen oder eine echte Zusammenführung hervorrufen. In den meisten Fällen ist es besser, die Arbeit mithilfe von Rebase zu kombinieren, als sie zusammenzuführen (zugegebenermaßen ist dies eine Frage des Geschmacks und der Meinung). In diesem Fall möchten Sie möglicherweise stattdessen git rebase Verwenden. Wenn Sie jedoch niemals eigene Commits für demo ausführen, benötigen Sie nicht einmal einen demo-Zweig . Alternativ können Sie git merge --ff-only Origin/demo Verwenden, wenn Sie vieles davon automatisieren möchten, aber sorgfältig prüfen können, ob es Commits gibt, die sowohl Sie als auch andere vorgenommen haben. Dadurch wird Ihr demo, um den aktualisierten Origin/demo - Wert nach Möglichkeit zu ermitteln. Andernfalls schlägt dies einfach fehl (an diesem Punkt können Sie die beiden Änderungssätze überprüfen und gegebenenfalls eine echte Zusammenführung oder eine erneute Basis auswählen).

Dieselbe Logik gilt für master, obwohl Sie die Zusammenführung für master durchführen, sodass Sie definitiv eine master. Es ist jedoch noch wahrscheinlicher, dass Sie möchten, dass die Zusammenführung fehlschlägt, wenn sie nicht als Nichtzusammenführung im Schnellvorlauf ausgeführt werden kann. Daher sollte dies wahrscheinlich auch git merge --ff-only Origin/master Sein.

Nehmen wir an, Sie machen niemals eigene Commits für demo. In diesem Fall können wir den Namen demo komplett weglassen:

git fetch Origin   # update Origin/*

git checkout master
git merge --ff-only Origin/master || die "cannot fast-forward our master"

git merge -X theirs Origin/demo || die "complex merge conflict"

git Push Origin master

Wenn Sie eigene demo-Verzweigungs-Commits ausführen , ist dies nicht hilfreich. Sie können auch die vorhandene Zusammenführung beibehalten (aber je nach gewünschtem Verhalten --ff-only hinzufügen) oder eine Neuzusammenführung durchführen. Beachten Sie, dass alle drei Methoden fehlschlagen können: Zusammenführen schlägt möglicherweise mit einem Konflikt fehl, Zusammenführen mit --ff-only Kann möglicherweise nicht schnell vorwärts ausgeführt werden, und erneutes Ausführen schlägt möglicherweise mit einem Konflikt fehl (erneutes Ausführen funktioniert im Wesentlichen mit Cherry-Picking Commits, die die Merge-Maschinerie verwenden und daher einen Merge-Konflikt verursachen können).

71
torek

Sie können "unsere" Option in Git Merge versuchen,

git merge branch -X ours

Diese Option erzwingt eine automatische Bereinigung widersprüchlicher Hunks, indem unsere Version bevorzugt wird. Änderungen von dem anderen Baum, die nicht mit unserer Seite in Konflikt stehen, werden in das Zusammenführungsergebnis übernommen. Bei einer Binärdatei wird der gesamte Inhalt von unserer Seite übernommen.

9
manuj

Ich hatte ein ähnliches Problem, bei dem ich alle Dateien, die Änderungen/Konflikte mit einem anderen Zweig aufwiesen, effektiv ersetzen musste.

Die Lösung, die ich gefunden habe, war die Verwendung von git merge -s ours branch.

Beachten Sie, dass die Option -s Und nicht -X Ist. -s Bezeichnet die Verwendung von ours als Mergestrategie der obersten Ebene. -X Würde die Option ours auf die Mergestrategie recursive anwenden , was ich (oder wir) in diesem Fall nicht wollen.

Schritte, bei denen oldbranch der Zweig ist, den Sie mit newbranch überschreiben möchten.

  • git checkout newbranch Checkt den Zweig aus, den Sie behalten möchten
  • git merge -s ours oldbranch Wird im alten Zweig zusammengeführt, behält aber alle unsere Dateien bei.
  • git checkout oldbranch Checkt den Zweig aus, den Sie überschreiben möchten
  • get merge newbranch Wird im neuen Zweig zusammengeführt und überschreibt den alten Zweig
5
Niall Mccormack