Come "git show" un commit di unione con output diff combinato anche quando ogni file modificato è d'accordo con uno dei genitori?


186

Dopo aver fatto una fusione "semplice" (una senza conflitti), di git showsolito mostra solo qualcosa di simile

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

Questo perché, per le fusioni, git showutilizza il formato diff combinato che omette i file che concordano con una delle versioni principali.

C'è un modo per forzare git a mostrare ancora tutte le differenze nella modalità diff combinata?

Fare git show -mmostrerà le differenze (usando le differenze a coppie rispettivamente tra la nuova e tutte le versioni principali), ma preferirei averlo con le differenze contrassegnate da +/- nelle rispettive colonne come nella modalità combinata.


1
@ Tilman Vogel: rivedi la risposta accettata - Sembra che ci siano risposte migliori
Jayan,

1
@Jayan Mentre le altre risposte sono più popolari perché contengono suggerimenti utili, in realtà non si avvicinano al mio problema in quanto fanno solo differenze bidirezionali. Stavo cercando un diff a tre vie.
Tilman Vogel,

Risposte:


-3

No, non c'è modo di farlo git show. Ma a volte sarebbe bello, e probabilmente sarebbe relativamente facile da implementare nel codice sorgente di Git (dopo tutto, devi solo dirgli di non tagliare quello che pensa sia un output estraneo), quindi la patch per farlo verrebbe probabilmente accettato dai manutentori git.

Fai attenzione a ciò che desideri, però; fondere un ramo con un cambio di una riga che è stato biforcuto tre mesi fa avrà ancora una differenza enorme rispetto alla linea principale, e quindi una tale differenza completa sarebbe quasi del tutto inutile. Ecco perché Git non lo mostra.


12
Per favore, non dire "nessun modo per farlo" nel modo più chiaro possibile - vedi altre risposte. Questo è molto fuorviante da dire.
kgadek,

1
git show HEAD ^ ... HEAD; # per la soluzione di @ hesham_EE.
Michael Dimmitt,

git show HEAD ~ 1 ... HEAD ~ 0 - solo nome; # sintassi migliore. Per i pr iteranti.
Michael Dimmitt,

256

Guarda il messaggio di commit:

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

notare la linea:

Merge: fc17405 ee2de56

prendere quei due ID di commit e invertirli. quindi per ottenere il diff che desideri, devi fare:

git diff ee2de56..fc17405

per mostrare solo i nomi dei file modificati:

git diff --name-only ee2de56..fc17405

e per estrarli, puoi aggiungerlo a gitconfig:

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

quindi usalo facendo:

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

Grazie per il suggerimento, ma penso che non risolva il mio problema. A causa del markup e della formattazione dei commenti limitati, ho aggiunto il mio commento alla tua risposta. Scusa per quello! Deve essere sottoposto a peer review fino a quando non sarà visibile.
Tilman Vogel,

6
Sembra che la mia modifica sia stata rifiutata. In sintesi: il tuo diff non mostra quali aggiunte provengono da quale ramo. E non puoi distinguere se le modifiche sono state aggiunte nel secondo o rimosse nel primo ramo.
Tilman Vogel,

45
Una soluzione migliore è git diff fc17405...ee2de56: questo mostrerà tutte le modifiche su ee2de56 che sono raggiungibili dai commit su fc17405, che credo sia quello che vuoi. Nota i 3 punti anziché due.
Kris Nuttycombe,

1
@KrisNuttycombe 3 punti e l'ordine. E il tuo commento è quello che stavo cercando, che penso sia più simile a quello che voleva l'OP.
Izkata,

@KrisNuttycombe Questo in qualche modo non funziona git log, il che mostra ancora tutti i commit, come la ..variante. ..e ...fare lo stesso per log, ma diffperché sono diversi !? Come posso ottenere un elenco di commit che sono stati uniti in questo ramo?
Rudie,

77

Una soluzione migliore (menzionata da @KrisNuttycombe):

git diff fc17405...ee2de56

per il commit della fusione:

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

per mostrare tutte le modifiche ee2de56che sono raggiungibili da commit on fc17405. Nota l'ordine degli hash di commit: è lo stesso mostrato nelle informazioni di unione:Merge: fc17405 ee2de56

Nota anche i 3 punti ...anziché due !

Per un elenco di file modificati, è possibile utilizzare:

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

Questo è esattamente quello che ero dopo +1.
geedoubleya,

Questo in realtà mostra il risultato di un conflitto di unione, mentre l'altra risposta no.
Pod

12

È possibile creare un ramo con HEAD impostato su un commit prima di unire. Quindi, puoi fare:

git merge --squash testing

Questo si fonderà, ma non impegnerà. Poi:

git diff

5

Sembra rispondere qui: https://public-inbox.org/git/7vd392ezhx.fsf@alter.siamese.dyndns.org/

Quindi, in modo simile, correndo

$ git diff --cc $ M $ M ^ 1 $ M ^ 2 $ (git merge-base $ M ^ 1 $ M ^ 2)

dovrebbe mostrare una patch combinata che spiega lo stato a $ M rispetto agli stati registrati nei suoi genitori e nella base di unione.


sai se uno strumento può essere configurato per visualizzare una tale differenza in modo affiancato, potenzialmente in poche colonne (come nella finestra di risoluzione dei conflitti di unione IntelliJ)? La tua risposta è proprio quella che stavo cercando
Max

@Max No, temo di no. Google "n-way visual diff" fornisce alcuni link, quindi ho provato quelli.
max630,

4

Penso che tu abbia solo bisogno di 'git show -c $ ref'. Provando questo nel repository git su a8e4a59 mostra un diff combinato (caratteri più / meno in una delle 2 colonne). Come menziona il manuale di git-show, praticamente delega a "git diff-tree", quindi quelle opzioni sembrano utili.


3
No, per un'unione "semplice", git show -c $refmostra lo stesso output che ho citato, ovvero nessuna differenza. -cseleziona una modalità diff combinata molto simile alla modalità predefinita per i merge commit che è '--cc', vedi git help showe git help diff-tree. Entrambi omettono completamente i file che concordano con una delle versioni principali di quel file.
Tilman Vogel,

a8e4a59anzi, non rientra nella categoria di commit di merge, intendo. Questo commit di unione contiene infatti un file che differisce da entrambe le sue versioni principali. Documentation/git-fast-import.txtha alcune cose aggiunte da un genitore e alcune dall'altro. Ciò comporta un output non vuoto da git diff-tree --cc. Tuttavia, vengono visualizzate solo le modifiche in questo caso "in conflitto". Tutti i risultati di unione "puliti", guarda git show -m a8e4a59, non sono mostrati affatto.
Tilman Vogel,

1
@TilmanVogel: Grazie per aver sottolineato che le unioni di file "non interessanti" vengono escluse git show -cdall'output. (man git-diff-tree Non dire "Inoltre, elenca solo i file che sono stati modificati da tutti i genitori." Ma io per un certo aveva notato che.)
Paul Whittaker

3

nel tuo caso devi solo

git diff HEAD^ HEAD^2

o solo hash per te commetti:

git diff 0e1329e55^ 0e1329e55^2

4
No, questo fa semplicemente una differenza bidirezionale tra i due genitori. Quello che stavo chiedendo era una modalità che mostra simultaneamente la differenza tra git merge-base HEAD^ HEAD^2e HEAD^e HEAD^2nello stesso stile che viene fatto per i file che sono stati uniti ai conflitti.
Tilman Vogel,

3

Se il commit di merge è commit 0e1329e5, come sopra, puoi ottenere il diff contenuto in questa unione:

git diff 0e1329e5^..0e1329e5

Spero che aiuti!


3

Se sei seduto al commit di unione, questo mostra le differenze:

git diff HEAD~1..HEAD

Se non si esegue il commit di merge, è sufficiente sostituire HEAD con il commit di merge. Questo metodo sembra il più semplice e intuitivo.


1
Questo non è un output "combinato combinato". Ottenere differenze tra ogni coppia di genitori e HEAD non è un problema qui.
Tilman Vogel,

2

Puoi usare il comando diff-tree con il flag -c. Questo comando mostra quali file sono stati modificati nel commit di unione.

git diff-tree -c {merged_commit_sha}

Ho ottenuto la descrizione della bandiera -c da Git-Scm :

Questo flag cambia il modo in cui viene visualizzato un commit di unione (il che significa che è utile solo quando al comando viene dato uno o --stdin). Mostra le differenze tra ciascuno dei genitori rispetto al risultato della fusione contemporaneamente invece di mostrare la differenza a coppie tra un genitore e il risultato uno alla volta (che è ciò che fa l'opzione -m). Inoltre, elenca solo i file che sono stati modificati da tutti i genitori.



1

Ho costruito un approccio generale per eseguire varie operazioni sugli commit di una fusione.

Primo passo : aggiungi un alias a git modificando ~/.gitconfig:

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

Passaggio due : in ~/.githelpers, definire una funzione bash:

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 $@
}

Terzo passo : profitto!

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

Probabilmente c'è un sacco di spazio per migliorare qui, ho appena montato questo insieme per superare una situazione fastidiosa. Sentiti libero di deridere la mia sintassi e / o logica bash.


Si noti che si può decidere di cambiare "..." a ".." nel bit 'awk', a seconda di cosa avete bisogno e che il comando si sta eseguendo: stackoverflow.com/questions/462974/...
Nerdmaster
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.