Git mit Force Overwrite zusammenführen

98

Ich habe einen Zweig namens, demoden ich mit dem masterZweig zusammenführen muss. Ich kann das gewünschte Ergebnis mit folgenden Befehlen erhalten:

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 merge Fragen , die ich erzählen möchte gitzu überschreiben Änderungen in masterZweig ohne mir prompt fusionieren. Grundsätzlich sollten Änderungen in der demoVerzweigung Änderungen in der Verzweigung automatisch überschreiben master.

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

OpenStack
quelle
git push -f origin master
MD XF
4
@ MDXF: Vielleicht irre ich mich, aber sollte ich nicht -fOption mit mergeBefehl und nicht mit pushBefehl verwenden
OpenStack
Sie könnten beide ausprobieren und sehen, was für Sie funktioniert
MD XF
Siehe untenstehenden Link für eine Lösung zum Überschreiben von Kraft: stackoverflow.com/a/42454737/984471
Manohar Reddy Poreddy

Antworten:

97

Nicht wirklich mit dieser Antwort verbunden, aber ich würde Graben git pull, die nur läuft, git fetchgefolgt von git merge. Sie führen drei Zusammenführungen durch, wodurch Ihr Git drei Abrufvorgänge ausführt, wenn nur ein Abruf erforderlich ist. 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 der schwierigsten Zusammenführung

Der interessanteste Teil hier ist git merge -X theirs. Wie root545 feststellte , werden die -XOptionen an die Zusammenführungsstrategie weitergegeben, und sowohl die Standardstrategie recursiveals auch die alternative resolveStrategie nehmen -X oursoder -X theirs(die eine oder andere, aber nicht beide). Um zu verstehen, was sie tun, müssen Sie jedoch wissen, wie Git Konflikte zusammenführt und behandelt .

Ein Zusammenführungskonflikt kann in einigen Dateien 1 auftreten, wenn sich die Basisversion sowohl von der aktuellen (auch als lokale, HEAD- oder --ours) Version als auch von der anderen (auch als Remote- oder --theirs) Version derselben Datei bezeichnet wird, unterscheidet. Das heißt, bei der Zusammenführung wurden drei Revisionen (drei Commits) identifiziert: Base, unsere und ihre. Die "Basis" -Version stammt aus der Zusammenführungsbasis zwischen unserem Commit und ihrem Commit, wie im Commit-Diagramm angegeben (mehr dazu in anderen StackOverflow-Postings). Git hat dann zwei Arten von Änderungen gefunden: "Was wir getan haben" und "Was sie getan haben". Diese Änderungen werden (im Allgemeinen) zeilenweise rein textuell gefundenBasis. Git hat kein wirkliches Verständnis für Dateiinhalte; es wird lediglich jede Textzeile verglichen.

Diese Änderungen werden in der git diffAusgabe angezeigt und haben wie immer auch einen Kontext . Es ist möglich, dass Dinge, die wir geändert haben, in anderen Zeilen stehen als Dinge, die sie geändert haben, so dass die Änderungen so aussehen, als würden sie nicht kollidieren, aber der Kontext hat sich auch geändert (z. B. weil sich unsere Änderung am oberen oder unteren Rand der Datei befindet). Damit die Datei in unserer Version ausgeht, haben sie in ihrer Version auch oben oder unten mehr Text hinzugefügt.

Wenn die Änderungen in verschiedenen Zeilen erfolgen - zum Beispiel colorin colourZeile 17 und fredin barneyZeile 71 -, besteht kein Konflikt: Git übernimmt einfach beide Änderungen. 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, es sich jedoch um unterschiedliche Änderungen handelt oder wenn es sich um einen speziellen Fall eines störenden Kontexts handelt, wird ein Änderungs- / Änderungskonflikt angezeigt.

Die Optionen -X oursund -X theirsteilen 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 verschmelzen demo(ihre) mit master(unseren) und möchten die Änderungen von demo, möchten Sie -X theirs.

Das blinde Auftragen -Xist jedoch gefährlich. Nur weil unsere Änderungen nicht zeilenweise in Konflikt standen, heißt das nicht, dass unsere Änderungen nicht tatsächlich in Konflikt stehen! Ein klassisches Beispiel sind 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 sie ials Schleifenzähler. Wenn wir die beiden Änderungen kombinieren, wird der resultierende Code nicht mehr kompiliert. Die -XOption ist hier keine Hilfe, da sich die Änderungen in verschiedenen Zeilen befinden .

Wenn Sie über eine automatisierte Testsuite verfügen, müssen Sie die Tests nach dem Zusammenführen am wichtigsten ausführen. Sie können dies nach dem Festschreiben tun und die Probleme später bei Bedarf beheben. oder Sie können dies vor dem Festschreiben tun , indem Sie --no-commitdem git mergeBefehl hinzufügen . Wir werden die Details für all dies anderen Postings überlassen.


1 Sie können auch Konflikte in Bezug auf "dateiweite" Operationen bekommen, z. B. korrigieren wir möglicherweise die Schreibweise eines Wortes in einer Datei (damit wir eine Änderung haben) und sie löschen die gesamte Datei (so dass sie eine haben) löschen). Git wird diese Konflikte unabhängig von den -XArgumenten nicht alleine lösen .


Weniger Zusammenführungen und / oder intelligentere Zusammenführungen durchführen und / oder Rebase verwenden

In unseren beiden Befehlssequenzen gibt es drei Zusammenführungen. Das erste ist, origin/demoin die lokale zu bringen demo(Ihre Verwendungen, git pulldie, wenn Ihr Git sehr alt ist, nicht aktualisiert origin/demowerden können, aber das gleiche Endergebnis erzeugen). Das zweite ist , zu bringen origin/masterin master.

Mir ist nicht klar, wer aktualisiert demound / oder master. Wenn Sie Ihren eigenen Code in Ihren eigenen demoZweig schreiben und andere Code schreiben und in den demoZweig verschieben origin, kann diese Zusammenführung im ersten Schritt zu Konflikten führen oder eine echte Zusammenführung bewirken. Meistens ist es besser, Rebase zu verwenden, als zusammenzuführen, um Arbeit zu kombinieren (zugegebenermaßen ist dies eine Frage des Geschmacks und der Meinung). In diesem Fall möchten Sie möglicherweise git rebasestattdessen verwenden. Auf der anderen Seite, wenn Sie noch nie auf einem Ihren eigenen Commits tun demo, tun Sie nicht einmal brauchen einen demoZweig. Wenn Sie alternativ viel davon automatisieren möchten, aber sorgfältig prüfen können, ob Commits vorliegen, die sowohl Sie als auch andere vorgenommen haben, möchten Sie diese möglicherweise verwendengit merge --ff-only origin/demo: Dies spult Sie schnell vor demo, um mit den aktualisierten origin/demoDaten übereinzustimmen, wenn dies möglich ist, und schlägt einfach fehl, wenn nicht (an diesem Punkt können Sie die beiden Änderungssätze überprüfen und je nach Bedarf eine echte Zusammenführung oder eine Neuausrichtung auswählen).

Die gleiche Logik gilt für master, obwohl Sie den merge tun auf master , so dass Sie auf jeden Fall ein brauchen master. Es ist jedoch noch wahrscheinlicher, dass die Zusammenführung fehlschlagen soll, wenn sie nicht als Nicht-Zusammenführung im Schnellvorlauf durchgeführt werden kann git merge --ff-only origin/master. Dies sollte also wahrscheinlich auch so sein .

Nehmen wir an, Sie machen niemals Ihre eigenen Verpflichtungen demo. In diesem Fall können wir den Namen demoganz fallen lassen:

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 sich Ihr eigenes tun demoZweig Commits, ist dies nicht hilfreich; Sie können die vorhandene Zusammenführung auch --ff-onlybeibehalten (aber je nach gewünschtem Verhalten hinzufügen ) oder auf eine Neueinstellung umstellen. Beachten Sie, dass alle drei Methoden möglicherweise fehlschlagen: Das Zusammenführen kann mit einem Konflikt fehlschlagen, das Zusammenführen mit --ff-onlykann möglicherweise nicht schnell vorgespult werden, und das erneute Basieren kann mit einem Konflikt fehlschlagen (das erneute Basieren funktioniert im Wesentlichen durch Cherry-Picking- Commits, bei denen das Zusammenführen verwendet wird Maschinen und können daher einen Zusammenführungskonflikt bekommen).

torek
quelle
19

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

Die Lösung, die ich fand, war zu verwenden git merge -s ours branch.

Beachten Sie, dass die Option ist -sund nicht -X. -sbezeichnet die Verwendung oursals Zusammenführungsstrategie der obersten Ebene, -Xwürde die oursOption auf die recursiveZusammenführungsstrategie anwenden , was in diesem Fall nicht das ist, was ich (oder wir) wollen.

Schritte, wo oldbranchist der Zweig, mit dem Sie überschreiben möchten newbranch.

  • 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 jedoch alle unsere Dateien bei.
  • git checkout oldbranch checkt den Zweig aus, den Sie überschreiben möchten
  • get merge newbranch wird in der neuen Niederlassung zusammengeführt und überschreibt die alte Niederlassung
Niall Mccormack
quelle
Hinweis: Keine der anderen Lösungen hier hat für mich funktioniert, daher poste ich meine Antwort.
Niall Mccormack
1
Bei mir hat es nicht funktioniert. Es hat den Konflikt gelöst (die in Konflikt stehenden Dateien gelöst), aber die Datei wird nicht zusammengeführt. Und kann auch nicht zusammenführen.
c-an
Wenn jemand stecken bleibt und Sie aufgefordert werden, "Bitte geben Sie eine Festschreibungsnachricht ein, um zu erklären, warum diese Zusammenführung erforderlich ist": Geben Sie Ihre Nachricht ein, drücken Sie die ESC-Taste auf Ihrer Tastatur, geben Sie: wq ein und drücken Sie die EINGABETASTE, um die Eingabeaufforderung zu beenden.
topherPedersen
17

Dieser Zusammenführungsansatz fügt ein Commit hinzu, auf masterdas in was auch immer eingefügt wird feature, ohne sich über Konflikte oder anderen Mist zu beschweren.

Geben Sie hier die Bildbeschreibung ein

Bevor Sie etwas berühren

git stash
git status # if anything shows up here, move it to your desktop

Nun bereite den Meister vor

git checkout master
git pull # if there is a problem in this step, it is outside the scope of this answer

Lassen Sie sich featurealle gekleidet

git checkout feature
git merge --strategy=ours master

Mach den Kill

git checkout master
git merge --no-ff feature
William Entriken
quelle
1
Git Push to Finish
Kochchy
git-scm.com/docs/git-merge#Documentation/git-merge.txt-ours. Es hat funktioniert, wenn die Commits nicht sauber zusammengeführt wurden. Dieser Ansatz wird jedoch nicht immer funktionieren, um die Quelle zu zitieren Changes from the other tree that do not conflict with our side are reflected in the merge result. Es hat bei mir nicht funktioniert, da ich Commits in meiner Filiale, die überschrieben wurden, sauber zusammengeführt hatte. Gibt es einen anderen Weg?
NiharGht
11

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

Git Merge Branch -X unsere

Diese Option erzwingt, dass widersprüchliche Hunks automatisch automatisch aufgelöst werden, indem unsere Version bevorzugt wird. Änderungen gegenüber dem anderen Baum, die nicht mit unserer Seite in Konflikt stehen, werden im Zusammenführungsergebnis berücksichtigt. Bei einer Binärdatei wird der gesamte Inhalt von unserer Seite übernommen.

manuj
quelle
3
Dies wäre rückwärts, da der OP sagte, er wolle, dass die demoVersion bevorzugt wird, obwohl er sich zusammenschließt master. Es gibt -X theirsauch, aber es ist nicht klar, dass dies das ist, was das OP wirklich will.
Torek
Sie haben nicht den ganzen Weg gelesen. In Ihrem Hinweis wird beschrieben, was oursbei der Verwendung im Backend mit der -sOption geschieht . Bei Verwendung oursmit -X: Es verwirft alles, was der andere Baum getan hat, und erklärt, dass unser Verlauf alles enthält, was darin passiert ist. Quelle
Jimasun
2

Als ich versuchte, -X theirsandere verwandte Befehlsschalter zu verwenden, bekam ich immer wieder ein Merge-Commit. Ich habe es wahrscheinlich nicht richtig verstanden. Eine leicht verständliche Alternative besteht darin, den Zweig zu löschen und ihn dann erneut zu verfolgen.

git branch -D <branch-name>
git branch --track <branch-name> origin/<branch-name>

Dies ist nicht gerade eine "Zusammenführung", aber das ist es, wonach ich gesucht habe, als ich auf diese Frage gestoßen bin. In meinem Fall wollte ich Änderungen von einem entfernten Zweig abrufen, die zwangsweise gedrückt wurden.

Matt
quelle