Wie kann ein Merge-Commit mit kombinierter Diff-Ausgabe angezeigt werden, selbst wenn jede geänderte Datei mit einem der Elternteile übereinstimmt?


184

Nach einer "einfachen" Zusammenführung (eine ohne Konflikte) wird git shownormalerweise nur so etwas angezeigt

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

Merge branch 'testing' into master

Dies liegt daran, dass für Zusammenführungen git showdas kombinierte Diff-Format verwendet wird, bei dem Dateien weggelassen werden, die mit einer der übergeordneten Versionen übereinstimmen.

Gibt es eine Möglichkeit, git zu zwingen, im kombinierten Diff-Modus immer noch alle Unterschiede anzuzeigen?

git show -mWenn Sie dies tun, werden die Unterschiede angezeigt (unter Verwendung paarweiser Unterschiede zwischen der neuen und allen übergeordneten Versionen), aber ich würde es vorziehen, wenn die Unterschiede in den jeweiligen Spalten mit +/- gekennzeichnet sind, wie im kombinierten Modus.


1
@ Tilman Vogel: Bitte überprüfen Sie die akzeptierte Antwort - Sieht aus wie es bessere Antworten gibt
Jayan

1
@Jayan Während die anderen Antworten populärer sind, weil sie nützliche Hinweise enthalten, kommen sie meinem Problem nicht näher, da sie nur Zwei-Wege-Unterschiede machen. Ich suchte nach einem Drei-Wege-Diff.
Tilman Vogel

Antworten:


-3

Nein, damit gibt es keine Möglichkeit git show. Aber manchmal wäre es sicherlich nett, und es wäre wahrscheinlich relativ einfach, es im Git-Quellcode zu implementieren (schließlich muss man ihm nur sagen, dass er nicht herausschneiden soll, was er für eine fremde Ausgabe hält), also den Patch, um dies zu tun würde wahrscheinlich von den Git-Betreuern akzeptiert werden.

Seien Sie jedoch vorsichtig, was Sie sich wünschen. Das Zusammenführen eines Zweigs mit einer einzeiligen Änderung, die vor drei Monaten gegabelt wurde, hat immer noch einen großen Unterschied zur Hauptlinie, und daher wäre ein solcher vollständiger Unterschied fast völlig nicht hilfreich. Deshalb zeigt git es nicht.


12
Bitte sagen Sie nicht "keine Möglichkeit, dies zu tun", da dies eindeutig möglich ist - sehen Sie andere Antworten. Das ist sehr irreführend zu sagen.
kgadek

1
Git Show HEAD ^ ... HEAD; # per @ hesham_EEs Lösung.
Michael Dimmitt

git show HEAD ~ 1 ... HEAD ~ 0 - nur Name; # bessere Syntax. Zum Iterieren von Prs.
Michael Dimmitt

255

Sehen Sie sich die Commit-Nachricht an:

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

Merge branch 'testing' into master

Beachten Sie die Zeile:

Merge: fc17405 ee2de56

Nehmen Sie diese beiden Commit-IDs und kehren Sie sie um. Um den gewünschten Diff zu erhalten, würden Sie Folgendes tun:

git diff ee2de56..fc17405

um nur die Namen der geänderten Dateien anzuzeigen:

git diff --name-only ee2de56..fc17405

und um sie zu extrahieren, können Sie dies zu Ihrer gitconfig hinzufügen:

exportfiles = !sh -c 'git diff $0 --name-only | "while read files; do mkdir -p \"$1/$(dirname $files)\"; cp -vf $files $1/$(dirname $files); done"'

Verwenden Sie es dann, indem Sie Folgendes tun:

git exportfiles ee2de56..fc17405 /c/temp/myproject

Vielen Dank für den Vorschlag, aber ich denke, er löst mein Problem nicht. Aufgrund der eingeschränkten Kommentierung und Formatierung von Kommentaren habe ich meinen Kommentar zu Ihrer Antwort hinzugefügt. Das tut mir leid! Muss einer Peer-Review unterzogen werden, bis sie sichtbar ist.
Tilman Vogel

6
Scheint, meine Bearbeitung wurde abgelehnt. Zusammenfassend: Ihr Diff zeigt nicht an, welche Ergänzungen aus welchem ​​Zweig stammen. Und Sie können nicht unterscheiden, ob Änderungen im zweiten Zweig hinzugefügt oder im ersten Zweig entfernt wurden.
Tilman Vogel

45
Eine bessere Lösung ist git diff fc17405...ee2de56- dies zeigt alle Änderungen an ee2de56, die durch Commits auf fc17405 erreichbar sind, was meiner Meinung nach das ist, was Sie wollen. Beachten Sie die 3 Punkte anstelle von zwei.
Kris Nuttycombe

1
@KrisNuttycombe 3 Punkte und die Reihenfolge. Und Ihr Kommentar ist das, wonach ich gesucht habe, was meiner Meinung nach eher dem entspricht, was das OP wollte.
Izkata

@KrisNuttycombe Das funktioniert irgendwie nicht mit git log, was immer noch alle Commits anzeigt, wie die ..Variante. ..und ...mach das gleiche fürlog , aber für diffsie sind anders!? Wie erhalte ich eine Liste der Commits, die in diesem Zweig zusammengeführt wurden?
Rudie

77

Eine bessere Lösung (von @KrisNuttycombe erwähnt):

git diff fc17405...ee2de56

für das Merge-Commit:

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

um alle Änderungen ee2de56anzuzeigen, die ab Commits erreichbar sind fc17405. Beachten Sie die Reihenfolge der Commit-Hashes - sie entspricht der Reihenfolge in den Zusammenführungsinformationen:Merge: fc17405 ee2de56

Beachten Sie auch die 3 Punkte ...anstelle von zwei !

Für eine Liste der geänderten Dateien können Sie Folgendes verwenden:

git diff fc17405...ee2de56 --name-only

Genau das war ich nach +1.
Geedoubleya

Dies zeigt tatsächlich das Ergebnis eines Zusammenführungskonflikts, während die andere Antwort dies nicht tut.
Pod

12

Sie können einen Zweig erstellen, bei dem HEAD vor dem Zusammenführen auf ein Commit festgelegt ist. Dann können Sie Folgendes tun:

git merge --squash testing

Dies wird zusammengeführt, aber nicht festgeschrieben. Dann:

git diff

5

Scheint hier beantwortet zu sein: https://public-inbox.org/git/7vd392ezhx.fsf@alter.siamese.dyndns.org/

Also in ähnlicher Weise laufen

$ git diff --cc $ M $ M ^ 1 $ M ^ 2 $ (Git-Merge-Basis $ M ^ 1 $ M ^ 2)

sollte einen kombinierten Patch anzeigen, der den Status bei $ M im Verhältnis zu den in seinen Eltern aufgezeichneten Status und der Zusammenführungsbasis erklärt.


Wissen Sie, ob ein Tool so konfiguriert werden kann, dass ein solcher Unterschied nebeneinander angezeigt wird, möglicherweise in wenigen Spalten (wie im Fenster zur Lösung von Konflikten bei der Zusammenführung von IntelliJ)? Ihre Antwort ist genau das, wonach ich gesucht habe
Max

@ Max Nein, ich fürchte, ich nicht. Das Googeln von "n-way visual diff" bietet einige Links, also habe ich diese ausprobiert.
max630

4

Ich denke du brauchst nur 'git show -c $ ref'. Wenn Sie dies im Git-Repository auf a8e4a59 versuchen, wird ein kombinierter Unterschied angezeigt (Plus- / Minuszeichen in einer von 2 Spalten). Wie im git-show-Handbuch erwähnt, delegiert es so ziemlich an 'git diff-tree', sodass diese Optionen nützlich aussehen.


3
Nein, für eine "einfache" Zusammenführung wird git show -c $refdieselbe Ausgabe angezeigt, die ich zitiert habe, dh keine Unterschiede. -cwählt einen kombinierten Diff-Modus aus, der dem Standardmodus für Merge-Commits sehr ähnlich ist: '--cc', siehe git help showund git help diff-tree. In beiden Fällen werden Dateien, die mit einer der übergeordneten Versionen dieser Datei übereinstimmen, vollständig weggelassen.
Tilman Vogel

a8e4a59in der Tat fällt nicht in die Kategorie der Merge Commits, meine ich. Dieses Zusammenführungs-Commit enthält tatsächlich eine Datei, die sich von den beiden übergeordneten Versionen unterscheidet. Documentation/git-fast-import.txthat einige Dinge von einem Elternteil und einige von dem anderen hinzugefügt. Dies führt zu einer nicht leeren Ausgabe von git diff-tree --cc. Es werden jedoch nur die Änderungen in diesem "widersprüchlichen" Fall angezeigt. Alle "sauberen" Zusammenführungsergebnisse git show -m a8e4a59werden überhaupt nicht angezeigt.
Tilman Vogel

1
@ TilmanVogel: Vielen Dank für den Hinweis, dass "uninteressante" Dateizusammenführungen in der git show -cAusgabe nicht berücksichtigt werden. ( man git-diff-treesagt "Außerdem listet es nur Dateien auf, die von allen Eltern geändert wurden.", aber ich jedenfalls hatte das sicherlich nicht entdeckt.)
Paul Whittaker

3

in deinem Fall musst du nur

git diff HEAD^ HEAD^2

oder nur Hash für Sie begehen:

git diff 0e1329e55^ 0e1329e55^2

4
Nein, dies ist nur ein einfacher Unterschied zwischen den beiden Elternteilen. Was ich gefragt habe, war ein Modus, der gleichzeitig den Unterschied zwischen git merge-base HEAD^ HEAD^2und HEAD^und HEAD^2im gleichen Stil anzeigt, wie dies bei Dateien der Fall ist, die mit Konflikten zusammengeführt wurden.
Tilman Vogel

3

Wenn Ihr Merge-Commit wie oben Commit 0e1329e5 lautet, können Sie den Diff, der in diesem Merge-Commit enthalten war, abrufen, indem Sie:

git diff 0e1329e5^..0e1329e5

Ich hoffe das hilft!


3

Wenn Sie beim Zusammenführungs-Commit sitzen, zeigt dies die Unterschiede:

git diff HEAD~1..HEAD

Wenn Sie nicht am Merge-Commit teilnehmen, ersetzen Sie HEAD einfach durch das Merge-Commit. Diese Methode scheint die einfachste und intuitivste zu sein.


1
Dies ist keine "kombinierte Diff" -Ausgabe. Unterschiede zwischen jedem Elternpaar und HEAD zu bekommen, ist hier kein Problem.
Tilman Vogel

2

Sie können den Befehl diff-tree mit dem Flag -c verwenden. Dieser Befehl zeigt Ihnen, welche Dateien sich beim Zusammenführungs-Commit geändert haben.

git diff-tree -c {merged_commit_sha}

Ich habe die Beschreibung der Flagge -c von Git-Scm erhalten :

Dieses Flag ändert die Art und Weise, wie ein Zusammenführungs-Commit angezeigt wird (was bedeutet, dass es nur nützlich ist, wenn der Befehl eins oder --stdin erhält). Es zeigt die Unterschiede zwischen jedem Elternteil und dem Zusammenführungsergebnis gleichzeitig an, anstatt paarweise Unterschiede zwischen einem Elternteil und dem Ergebnis nacheinander anzuzeigen (was bei der Option -m der Fall ist). Außerdem werden nur Dateien aufgelistet, die von allen Eltern geändert wurden.


2
Sieht nach einem guten Artikel zu diesem Thema aus: haacked.com/archive/2014/02/21/reviewing-merge-commits und vielleicht auch so: longair.net/blog/2009/04/16/git-fetch-and-merge
Devin G Rhode

1

Ich habe einen universellen Ansatz entwickelt, um verschiedene Operationen an den Commits einer Fusion durchzuführen.

Erster Schritt : Fügen Sie git einen Alias ​​hinzu, indem Sie Folgendes bearbeiten ~/.gitconfig:

[alias]
  range = "!. ~/.githelpers && run_on_merge_range"

Schritt 2 : ~/.githelpersDefinieren Sie in eine Bash-Funktion:

run_on_merge_range() {
  cmd=$1; shift
  commit=$1; shift
  range=$(git show $commit | grep Merge: | awk '{print $2 "..." $3}')
  echo "git $cmd $range $@"
  if [ -z $range ]; then
    echo "No merge detected"
    exit 1
  fi
  git $cmd $range $@
}

Schritt drei : Profitieren Sie!

git range log <merge SHA> --oneline
git range diff <merge SHA> --reverse -p
git range diff <merge SHA> --name-only

Hier gibt es wahrscheinlich viel Raum für Verbesserungen. Ich habe dies nur zusammengepeitscht, um eine nervige Situation zu überwinden. Fühlen Sie sich frei, meine Bash-Syntax und / oder Logik zu verspotten.


Beachten Sie, dass Sie im Bit "awk" möglicherweise "..." in ".." ändern möchten, je nachdem, was Sie benötigen und welchen Befehl Sie ausführen
Nerdmaster
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.