Wie kann ich eine Vorschau einer Zusammenführung in Git anzeigen?

397

Ich habe einen Git-Zweig (zum Beispiel die Hauptlinie) und möchte in einem anderen Entwicklungszweig zusammengeführt werden. Oder tue ich?

Um zu entscheiden, ob ich diesen Zweig wirklich zusammenführen möchte, möchte ich eine Vorschau der Zusammenführung sehen. Vorzugsweise mit der Möglichkeit, die Liste der angewendeten Commits anzuzeigen.

Bisher ist das Beste, was ich mir einfallen lassen kann merge --no-ff --no-commit, und dann diff HEAD.

Glenjamin
quelle
17
Ich würde nur git mergeund git reset --keep HEAD@{1}wenn mir das Ergebnis nicht gefällt.
Jan Hudec
3
Beachten Sie, dass das Anzeigen der Liste der Commits mit ihrem Diff nicht unbedingt die ganze Geschichte erzählt. Wenn die Zusammenführung nicht trivial ist und insbesondere Konflikte vorliegen, ist das tatsächliche Ergebnis der Zusammenführung möglicherweise etwas interessant.
Cascabel
2
Ihre ursprüngliche Methode macht genau das. Der Punkt meines Kommentars ist, dass die Betrachtung einzelner Unterschiede zwar gut und schön ist, Sie jedoch bei einer komplexen Zusammenführung überraschende Ergebnisse erzielen können, selbst wenn alle zusammengeführten Commits unabhängig voneinander gut sind.
Cascabel
2
@Jan: Aus irgendwelchen Gründen, git reset --keep HEAD@{1}zurückgegeben fatal: Cannot do a keep reset in the middle of a merge.Hilfe?
Moey
3
Warum gibt es --previewbei git-merge keine Option?
Gaui

Antworten:

283

Ich habe festgestellt, dass die für mich am besten geeignete Lösung darin besteht , die Zusammenführung einfach durchzuführen und abzubrechen, wenn Konflikte auftreten . Diese spezielle Syntax fühlt sich für mich sauber und einfach an. Dies ist Strategie 2 unten.

Wenn Sie jedoch sicherstellen möchten, dass Sie Ihren aktuellen Zweig nicht durcheinander bringen oder einfach nicht bereit sind, unabhängig vom Vorhandensein von Konflikten zusammenzuführen, erstellen Sie einfach einen neuen Unterzweig daraus und führen Sie Folgendes zusammen:

Strategie 1: Der sichere Weg - eine temporäre Niederlassung zusammenführen:

git checkout mybranch
git checkout -b mynew-temporary-branch
git merge some-other-branch

Auf diese Weise können Sie den temporären Zweig einfach wegwerfen, wenn Sie nur die Konflikte sehen möchten. Sie müssen sich nicht die Mühe machen, die Zusammenführung "abzubrechen", und Sie können zu Ihrer Arbeit zurückkehren. Überprüfen Sie einfach "mybranch" erneut, und Sie haben keinen zusammengeführten Code oder Zusammenführungskonflikte in Ihrer Branche.

Dies ist im Grunde ein Trockenlauf.

Strategie 2: Wenn Sie definitiv zusammenführen möchten, aber nur, wenn es keine Konflikte gibt

git checkout mybranch
git merge some-other-branch

Wenn git Konflikte meldet (und NUR WENN ES Konflikte gibt), können Sie Folgendes tun:

git merge --abort

Wenn die Zusammenführung erfolgreich ist, können Sie sie nicht abbrechen (nur zurücksetzen).

Wenn Sie nicht zum Zusammenführen bereit sind, verwenden Sie den oben beschriebenen sichereren Weg.

[EDIT: 2016-Nov - Ich habe Strategie 1 gegen 2 getauscht, weil es so scheint, als ob die meisten Leute nach "dem sicheren Weg" suchen. Strategie 2 ist jetzt eher eine Anmerkung, dass Sie die Zusammenführung einfach abbrechen können, wenn die Zusammenführung Konflikte aufweist, mit denen Sie nicht fertig werden können. Denken Sie daran, wenn Sie Kommentare lesen!]

Kasapo
quelle
2
+1 für Strategie 2. Temporärer Zweig, der genau anzeigt, was beim Zusammenführen passiert. Strategie 1 versuche ich für diesen speziellen Fall zu vermeiden.
Gordolio
2
Ich schlage vor, die Strategien so zu ändern, dass die sicherere zuerst kommt (mein psychisches Training kommt durch - die meisten Leute würden annehmen, dass die beste Option die erste ist, trotz der klaren Verwendung des Wortes "sicherer"), aber ansonsten ausgezeichnet Job.
Paxdiablo
6
Sie können dies tun, git merge --no-ff --no-commitwenn Sie die Änderungen nicht direkt übernehmen möchten. Dies beseitigt die "Notwendigkeit" für einen anderen Zweig und macht es ein kleines bisschen einfacher, die Änderungen zu überprüfen, imo.
Gerard van Helden
und wenn Sie sich entscheiden, dass Sie überhaupt nicht zusammenführen möchten und tatsächlich lieber mehr Code schreiben und dann in Ihren Zweig einbinden möchten, damit Sie NUR Ihren Zweig auf einem Testserver bereitstellen können, müssten Sie dann nicht immer noch den Code zurücksetzen git merge --no-ff --no-commit? Ich denke, du kannst danach noch eine machen git merge --abort, wenn dir nicht gefällt, was du siehst? Auch wenn die Zusammenführung keine Konflikte erzeugt?
Kasapo
Die meisten Leute kopieren und fügen gerne ein und denken nicht zu viel nach. Fügen Sie daher für Strategie 1 möglicherweise auch hinzu, wie die Zusammenführung in der temporären lokalen Verzweigung git reset --hard HEADabgebrochen werden soll, git checkout <different branch name>und checken Sie dann eine andere Verzweigung aus und löschen Sie die temporäre Verzweigung git delete -b <name of temporary branch>.
user3613932
401
  • git log ..otherbranch
    • Liste der Änderungen, die in den aktuellen Zweig übernommen werden.
  • git diff ...otherbranch
    • unterscheiden sich vom gemeinsamen Vorfahren (Zusammenführungsbasis) zum Kopf dessen, was zusammengeführt wird. Beachten Sie die drei Punkte , die im Vergleich zu zwei Punkten eine besondere Bedeutung haben (siehe unten).
  • gitk ...otherbranch
    • grafische Darstellung der Zweige seit ihrer letzten Zusammenführung.

Leere Zeichenfolge impliziert HEAD, deshalb nur ..otherbranchstatt HEAD..otherbranch.

Die zwei gegen drei Punkte haben für diff eine etwas andere Bedeutung als für die Befehle, die Revisionen auflisten (log, gitk usw.). Für log und andere bedeutet zwei Punkte ( a..b) alles, was drin ist, baber nicht, aund drei Punkte ( a...b) bedeuten alles, was nur in einem von aoder ist b. Aber diff arbeitet mit zwei Revisionen und dort ist der einfachere Fall, der durch zwei Punkte ( a..b) dargestellt wird, ein einfacher Unterschied von abis bund drei Punkte ( a...b) bedeuten den Unterschied zwischen dem gemeinsamen Vorfahren und b( git diff $(git merge-base a b)..b).

Jan Hudec
quelle
7
Der dritte Punkt war der Teil, den ich vermisst habe, danke! Der Log-Ansatz funktioniert auch gut, log -p --reverse ..otherbranch scheint ein guter Weg zu sein, um zu sehen, was zusammengeführt werden würde.
Glenjamin
1
Ich wurde vermisst, git checkout masterbevor ich es versuchte. Ich fragte mich, warum es hieß, alle meine Änderungen würden
überschrieben werden
5
git show ..otherbranchzeigt eine Liste der Änderungen und Unterschiede an, die in den aktuellen Zweig eingefügt werden.
Gaui
4
Dies ist nicht ganz genau, insbesondere bei Kirschpicks.
void.pointer
2
@ void.pointer, git behandelt Cherry-Picks nicht speziell beim normalen Zusammenführen, also auch hier nicht. Es könnte eine Zusammenführungsstrategie geschrieben werden, die dies tun würde, aber soweit ich weiß, war dies niemals der Fall.
Jan Hudec
19

Wenn Sie wie ich sind, suchen Sie nach einem Äquivalent zu svn update -n. Das Folgende scheint den Trick zu tun. Beachten Sie, dass Sie zuerst einen Schritt machen müssen, git fetchdamit Ihr lokales Repo über die entsprechenden Updates verfügt, mit denen Sie vergleichen können.

$ git fetch origin
$ git diff --name-status origin/master
D       TableAudit/Step0_DeleteOldFiles.sh
D       TableAudit/Step1_PopulateRawTableList.sh
A       manbuild/staff_companies.sql
M       update-all-slave-dbs.sh

oder wenn Sie einen Unterschied von Ihrem Kopf zur Fernbedienung wünschen:

$ git fetch origin
$ git diff origin/master

IMO ist diese Lösung viel einfacher und weniger fehleranfällig (und daher viel weniger riskant) als die Top-Lösung, die "Zusammenführen, dann Abbrechen" vorschlägt.

djschny
quelle
1
sollte sein $ git checkout target-branchund dann $ git diff --name-status ...branch-to-be-merged(drei Punkte sind wichtig, also
tippe
Eines fehlt: Es zeigt Ihnen nicht, welche Dateien einen Konflikt haben würden - sie haben dieselbe "M" -Markierung wie Dateien, die in der Verzweigung geändert wurden, aber ohne Konflikte zusammengeführt werden können.
Peterflynn
Vielleicht war es 2012 anders, aber heutzutage scheint es ziemlich zuverlässig zu sein, eine Zusammenführung abzubrechen. Daher halte ich es nicht für fair, dies derzeit als "viel einfacher und weniger fehleranfällig" zu bezeichnen.
David Z
8

Die meisten Antworten hier erfordern entweder ein sauberes Arbeitsverzeichnis und mehrere interaktive Schritte (schlecht für die Skripterstellung) oder funktionieren nicht in allen Fällen, z gleich.

Um wirklich zu sehen, was sich in der masterBranche ändern würde, wenn Sie sich developjetzt in die Branche einfügen würden :

git merge-tree $(git merge-base master develop) master develop

Da es sich um einen Installationsbefehl handelt, wird nicht erraten, was Sie meinen. Sie müssen explizit sein. Es färbt auch nicht die Ausgabe oder verwendet Ihren Pager, daher wäre der vollständige Befehl:

git merge-tree $(git merge-base master develop) master develop | colordiff | less -R

- https://git.seveas.net/previewing-a-merge-result.html

(Danke an David Normington für den Link)

PS:

Wenn Sie Zusammenführungskonflikte erhalten, werden diese mit den üblichen Konfliktmarkierungen in der Ausgabe angezeigt, z.

$ git merge-tree $(git merge-base a b ) a b 
added in both
  our    100644 78981922613b2afb6025042ff6bd878ac1994e85 a
  their  100644 61780798228d17af2d34fce4cfbdf35556832472 a
@@ -1 +1,5 @@
+<<<<<<< .our
 a
+=======
+b
+>>>>>>> .their

User @dreftymac macht einen guten Punkt: Dies macht es für die Skripterstellung ungeeignet, da Sie dies nicht einfach aus dem Statuscode abrufen können. Die Konfliktmarkierungen können je nach den Umständen sehr unterschiedlich sein (gelöscht oder geändert usw.), was es auch schwierig macht, sie zu erfassen. In acht nehmen.

hraban
quelle
1
@hraban Dies sieht nach der richtigen Antwort aus, es fehlt jedoch anscheinend noch ein Element. Bei diesem Ansatz muss der Benutzer die Ausgabe "mustern", um festzustellen, ob die Konfliktmarkierungen vorhanden sind. Haben Sie einen Ansatz, der einfach zurückkehrt, truewenn Konflikte vorliegen und falsewenn keine Konflikte vorliegen (z. B. ein boolescher Wert, für den kein "Augapfel" -Test oder menschliches Eingreifen erforderlich ist)?
Dreftymac
1
@dreftymac kann nichts in diesem Sinne finden. Sie könnten so etwas wie gebrauchen, git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to mergeaber es ist finnicky; Ich vergesse wahrscheinlich einen Fall. Vielleicht möchten Sie stattdessen nach Konfliktmarkierungen suchen? zB fängt dies wahrscheinlich nicht "ihre gelöschten, unsere geänderten" Stilkonflikte auf. (Ich habe gerade überprüft und das zeigt nicht einmal Konfliktmarkierungen, so dass Sie eine sorgfältige Regex benötigen, um hier sicher zu sein)
hraban
1
Verwenden Sie less -Rdiese Option , um farbige Ausgaben zu verarbeiten, ohne Ihre Konfiguration zu ändern.
Giacomo Alzetta
Danke @GiacomoAlzetta, ich habe es aktualisiert.
Hraban
6

Wenn Sie die Änderungen bereits abgerufen haben, ist mein Favorit:

git log ...@{u}

Das braucht Git 1.7.x, glaube ich allerdings. Die @{u}Notation ist eine "Abkürzung" für den Upstream-Zweig, daher ist sie etwas vielseitiger als git log ...origin/master.

Hinweis: Wenn Sie zsh und das erweiterte Glog-Ding verwenden, müssen Sie wahrscheinlich Folgendes tun:

git log ...@\{u\}
Pablo Olmos de Aguilera C.
quelle
6

Zusätzlich zu den vorhandenen Antworten kann ein Alias ​​erstellt werden, um den Unterschied und / oder das Protokoll vor einer Zusammenführung anzuzeigen. Bei vielen Antworten wird das fetchzuerst vorgenommene Auslassen weggelassen, bevor eine Vorschau der Zusammenführung angezeigt wird. Dies ist ein Alias, der diese beiden Schritte zu einem kombiniert (Emulation von etwas ähnlichem wie mercurial's hg incoming/ outgoing).

Aufbauend auf " git log ..otherbranch" können Sie Folgendes hinzufügen ~/.gitconfig:

...
[alias]
    # fetch and show what would be merged (use option "-p" to see patch)
    incoming = "!git remote update -p; git log ..@{u}"

Aus Gründen der Symmetrie kann der folgende Alias ​​verwendet werden, um anzuzeigen, was festgeschrieben wird und vor dem Verschieben übertragen werden würde:

    # what would be pushed (currently committed)
    outgoing = log @{u}..

Und dann können Sie " git incoming" ausführen , um viele Änderungen anzuzeigen, oder " git incoming -p", um den Patch (dh das "Diff"), " git incoming --pretty=oneline" für eine knappe Zusammenfassung usw. anzuzeigen. Sie können dann (optional) " git pull" ausführen tatsächlich verschmelzen. (Da Sie bereits abgerufen haben, kann die Zusammenführung direkt durchgeführt werden.)

Ebenso zeigt " git outgoing", was gedrückt würde, wenn Sie laufen würden " git push".

Michael
quelle
3

git log currentbranch..otherbranchSie erhalten eine Liste der Commits, die bei einer Zusammenführung in den aktuellen Zweig gelangen. Die üblichen zu protokollierenden Argumente, die Details zu den Commits enthalten, geben Ihnen weitere Informationen.

git diff currentbranch otherbranchgibt Ihnen den Unterschied zwischen den beiden Commits, die eins werden. Dies wird ein Unterschied sein, der Ihnen alles gibt, was zusammengeführt wird.

Würden diese helfen?

Noufal Ibrahim
quelle
2
Eigentlich falsch. git log otherbranch..currentbranchgibt eine Liste der Commits auf currentbranch an . Das git diff otherbranch currentbranchgibt Ihnen einen Unterschied von der zu verschmelzenden Version zum aktuellen Tipp, der so nutzlos wie möglich ist, da Sie sich von der Zusammenführungsbasis zum Zusammenführungskopf unterscheiden möchten.
Jan Hudec
Vielen Dank. Ich habe die Namen der Bäume geändert.
Noufal Ibrahim
3

Pull-Anfrage - Ich habe die meisten der bereits eingereichten Ideen verwendet, aber eine, die ich auch häufig verwende, ist (insbesondere wenn sie von einem anderen Entwickler stammt) eine Pull-Anfrage, die eine praktische Möglichkeit bietet, alle Änderungen in einer Zusammenführung zu überprüfen, bevor sie ausgeführt werden Ort. Ich weiß, dass GitHub kein Git ist, aber es ist sicher praktisch.

G-Man
quelle
2

Abgesehen davon, dass die Zusammenführung tatsächlich weggeworfen wird (siehe Kasapos Antwort), scheint es keinen verlässlichen Weg zu geben, dies zu sehen.

Trotzdem ist hier eine Methode, die nur geringfügig nahe kommt:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

Dies gibt einen fairen Hinweis darauf, welche Commits es in die Fusion schaffen werden. Fügen Sie hinzu, um Unterschiede zu sehen -p. Um die Dateinamen zu sehen, fügen Sie alle --raw, --stat, --name-only, --name-status.

Das Problem mit dem git diff TARGET_BRANCH...SOURCE_BRANCHAnsatz (siehe Jan Hudecs Antwort) ist, dass Sie Unterschiede für Änderungen sehen, die sich bereits in Ihrem Zielzweig befinden, wenn Ihr Quellzweig Cross Merges enthält.

Antak
quelle
1

Vielleicht kann dir das helfen? git-diff-tree - Vergleicht den Inhalt und den Modus von Blobs, die über zwei Baumobjekte gefunden wurden

Chugaister
quelle
1

Ich möchte den Befehl git merge nicht als Vorläufer für die Überprüfung widersprüchlicher Dateien verwenden. Ich möchte keine Zusammenführung durchführen, ich möchte potenzielle Probleme identifizieren, bevor ich sie zusammenführe - Probleme, die durch die automatische Zusammenführung möglicherweise vor mir verborgen werden. Die Lösung, nach der ich gesucht habe, besteht darin, wie git eine Liste von Dateien ausspuckt, die in beiden Zweigen geändert wurden und in Zukunft relativ zu einem gemeinsamen Vorfahren zusammengeführt werden. Sobald ich diese Liste habe, kann ich andere Dateivergleichstools verwenden, um die Dinge weiter zu untersuchen. Ich habe mehrmals gesucht und in einem nativen Git-Befehl immer noch nicht gefunden, was ich will.

Hier ist meine Problemumgehung, falls sie jemand anderem da draußen hilft:

In diesem Szenario habe ich einen Zweig namens QA, der seit der letzten Produktionsversion viele Änderungen aufweist. Unsere letzte Produktionsversion ist mit "15.20.1" gekennzeichnet. Ich habe einen anderen Entwicklungszweig namens new_stuff, den ich in den QA-Zweig einbinden möchte. Sowohl QA als auch new_stuff verweisen auf Commits, die (wie von gitk gemeldet) dem 15.20.1-Tag "folgen".

git checkout QA
git pull
git diff 15.20.1 --name-only > QA_files
git checkout new_stuff
git pull
git diff 15.20.1 --name-only > new_stuff_files
comm -12 QA_files new_stuff_files

Hier sind einige Diskussionen, die zeigen, warum ich daran interessiert bin, auf diese spezifischen Dateien abzuzielen:

Wie kann ich Git Merge vertrauen?

/software/199780/how-far-do-you-trust-automerge

Laura
quelle