¿Cómo “mostrar git” un commit de fusión con salida diff combinada incluso cuando cada archivo modificado concuerda con uno de los padres?

186

Después de hacer una fusión "simple" (una sin conflictos), git showgeneralmente solo muestra algo como

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

Esto se debe a que, para las fusiones, git showutiliza el formato de diferencias combinado que omite los archivos que coinciden con cualquiera de las versiones principales.

¿Hay alguna manera de forzar a git a que muestre todas las diferencias en el modo diff combinado?

Hacer git show -mmostrará las diferencias (usando las diferencias entre pares entre la nueva y todas las versiones principales, respectivamente), pero preferiría tener eso con las diferencias marcadas con +/- en las columnas respectivas, como en el modo combinado.

Tilman Vogel
fuente
1
@ Tilman Vogel: por favor revise la respuesta aceptada - Parece que hay mejores respuestas
Jayan
1
@Jayan Si bien las otras respuestas son más populares porque contienen sugerencias útiles, en realidad no se acercan a mi problema, ya que solo hacen diferencias de dos vías. Estaba buscando un diferencial de tres vías.
Tilman Vogel

Respuestas:

-3

No, no hay forma de hacer esto git show. Pero ciertamente sería bueno a veces, y probablemente sería relativamente fácil de implementar en el código fuente de git (después de todo, solo tiene que decirle que no recorte lo que cree que es una salida extraña), por lo que el parche para hacerlo probablemente sería aceptado por los mantenedores de git.

Sin embargo, ten cuidado con lo que deseas; fusionar una sucursal con un cambio de una línea que se bifurcó hace tres meses todavía tendrá una gran diferencia frente a la línea principal, por lo que una diferencia tan completa sería casi completamente inútil. Es por eso que git no lo muestra.

Apenwarr
fuente
12
Por favor, no diga "no hay forma de hacer esto", ya que es claramente posible; vea otras respuestas. Esto es muy engañoso de decir.
kgadek
1
git show HEAD ^ ... HEAD; Solución de # per @ hesham_EE.
Michael Dimmitt
git show HEAD ~ 1 ... HEAD ~ 0 - solo nombre; # mejor sintaxis. Para iterar pr's.
Michael Dimmitt
256

Mira el mensaje de confirmación:

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

observe la línea:

Merge: fc17405 ee2de56

tomar esos dos commit id y revertirlos. para obtener la diferencia que desea, debería hacer:

git diff ee2de56..fc17405

para mostrar solo los nombres de los archivos modificados:

git diff --name-only ee2de56..fc17405

y para extraerlos, puedes agregar esto a tu 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"'

luego úsalo haciendo:

git exportfiles ee2de56..fc17405 /c/temp/myproject
rip747
fuente
Gracias por la sugerencia, pero creo que no resuelve mi problema. Debido al marcado y formato de comentarios limitados, agregué mi comentario a su respuesta. ¡Lo siento por eso! Necesita ser revisado por pares hasta que sea visible.
Tilman Vogel
66
Parece que mi edición fue rechazada. En resumen: su diferencia no muestra qué adiciones provienen de qué rama. Y no puede distinguir si los cambios se agregaron en la segunda o se eliminaron en la primera rama.
Tilman Vogel
45
Una mejor solución es git diff fc17405...ee2de56: esto mostrará todos los cambios en ee2de56 a los que se puede acceder desde commits en fc17405, que creo que es lo que desea. Tenga en cuenta los 3 puntos en lugar de dos.
Kris Nuttycombe
1
@KrisNuttycombe 3 puntos y el orden. Y su comentario es lo que estaba buscando, que creo que es más parecido a lo que quería el OP.
Izkata
@KrisNuttycombe Esto de alguna manera no funciona git log, que todavía muestra todos los commits, como la ..variante. ..y ...hacer lo mismo para log, pero diffporque son diferentes? ¿Cómo obtengo una lista de confirmaciones que se fusionaron en esta rama?
Rudie
77

Una mejor solución (mencionada por @KrisNuttycombe):

git diff fc17405...ee2de56

para la confirmación de fusión:

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

para mostrar todos los cambios a los ee2de56que se puede acceder desde commits fc17405. Tenga en cuenta el orden de los hashes de confirmación: es el mismo que se muestra en la información de combinación:Merge: fc17405 ee2de56

¡También tenga en cuenta los 3 puntos en ...lugar de dos !

Para obtener una lista de los archivos modificados, puede usar:

git diff fc17405...ee2de56 --name-only
CodeManX
fuente
Esto es exactamente lo que estaba después de +1.
geedoubleya
En realidad, esto muestra el resultado de un conflicto de fusión, mientras que la otra respuesta no.
Pod
12

Puede crear una rama con HEAD establecida en una confirmación antes de fusionar. Entonces, puedes hacer:

git merge --squash testing

Esto se fusionará, pero no se comprometerá. Luego:

git diff
lado2k
fuente
5

Parece que se respondió aquí: https://public-inbox.org/git/[email protected]/

De manera similar, corriendo

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

debería mostrar un parche combinado que explique el estado en $ M en relación con los estados registrados en sus padres y la base de fusión.

max630
fuente
¿sabe si alguna herramienta puede configurarse para mostrar una diferencia de este tipo de manera paralela, potencialmente en pocas columnas (como en la ventana de resolución de conflictos de fusión IntelliJ)? Su respuesta es precisamente lo que estaba buscando
Max
@Max No, me temo que no. Buscar en Google "n-way visual diff" proporciona algunos enlaces, así que los probé.
max630
4

Creo que solo necesitas 'git show -c $ ref'. Probar esto en el repositorio de git en a8e4a59 muestra un diff combinado (caracteres más / menos en una de 2 columnas). Como menciona el manual de git-show, prácticamente delega a 'git diff-tree' para que esas opciones parezcan útiles.

patthoyts
fuente
3
No, para una fusión "simple", git show -c $refmuestra el mismo resultado que he citado, es decir, no hay diferencias. -cselecciona un modo diff combinado muy similar al modo predeterminado para commits de fusión que es '--cc', ver git help showy git help diff-tree. Ambos omiten por completo los archivos que están de acuerdo con cualquiera de las versiones principales de ese archivo.
Tilman Vogel
a8e4a59de hecho, no entra en la categoría de commits de fusión, quiero decir. Esta confirmación de fusión de hecho contiene un archivo que difiere de sus dos versiones principales. Documentation/git-fast-import.txttiene algunas cosas agregadas de uno de los padres y otras del otro. Esto da como resultado una salida no vacía de git diff-tree --cc. Sin embargo, solo se muestran los cambios en este caso "conflictivo". Todos los resultados de fusión "limpia", mira git show -m a8e4a59, no se muestran en absoluto.
Tilman Vogel
1
@TilmanVogel: Gracias por señalar que las fusiones de archivos "poco interesantes" quedan fuera de la git show -csalida. ( man git-diff-treedice "Además, enumera solo los archivos que fueron modificados de todos los padres", pero por mi parte, ciertamente no lo había visto.)
Paul Whittaker
3

en tu caso solo necesitas

git diff HEAD^ HEAD^2

o simplemente hash para que te comprometas:

git diff 0e1329e55^ 0e1329e55^2
gurugray
fuente
44
No, esto solo hace una diferencia bidireccional entre los dos padres. Lo que estaba pidiendo era una modalidad que muestra simultáneamente el diff entre el git merge-base HEAD^ HEAD^2y la HEAD^y HEAD^2en el mismo estilo que se realiza para los archivos que se fusionaron con los conflictos.
Tilman Vogel
3

Si su confirmación de fusión es commit 0e1329e5, como se indicó anteriormente, puede obtener la diferencia contenida en esta fusión mediante:

git diff 0e1329e5^..0e1329e5

¡Espero que esto ayude!

hesham_EE
fuente
3

Si está sentado en la confirmación de fusión, esto muestra las diferencias:

git diff HEAD~1..HEAD

Si no está en la confirmación de fusión, simplemente reemplace HEAD con la confirmación de fusión. Este método parece el más simple e intuitivo.

Bruce Dawson
fuente
1
Esta no es una salida "diff combinada". Obtener diferencias entre cada par de padres y HEAD no es un problema aquí.
Tilman Vogel
2

Puede usar el comando diff-tree con la bandera -c. Este comando le muestra qué archivos han cambiado en la confirmación de fusión.

git diff-tree -c {merged_commit_sha}

Obtuve la descripción de la bandera -c de Git-Scm :

Este indicador cambia la forma en que se muestra una confirmación de fusión (lo que significa que es útil solo cuando el comando recibe uno o --stdin). Muestra las diferencias de cada uno de los padres con el resultado de la fusión simultáneamente en lugar de mostrar las diferencias en pares entre un padre y el resultado, uno a la vez (que es lo que hace la opción -m). Además, solo enumera los archivos que fueron modificados de todos los padres.

Ehsan Mirsaeedi
fuente
2
Parece un buen artículo sobre este tema: haacked.com/archive/2014/02/21/reviewing-merge-commits y quizás esto también: longair.net/blog/2009/04/16/git-fetch-and-merge
Devin G Rhode
1

Desarrollé un enfoque de propósito general para realizar varias operaciones en los commits de una fusión.

Paso uno : Agregue un alias a git editando ~/.gitconfig:

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

Paso dos : En ~/.githelpers, defina una función 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 $@
}

Paso tres : ¡Ganancia!

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

Probablemente haya MUCHO margen de mejora aquí, simplemente lo combiné para superar una situación molesta. Siéntase libre de burlarse de mi sintaxis y / o lógica bash.

Nerdmaster
fuente
Tenga en cuenta que es posible que desee cambiar "..." a ".." en el bit "awk", según lo que necesite y el comando que esté ejecutando: stackoverflow.com/questions/462974/…
Nerdmaster