practices - git tag remove
git show de un merge commit (2)
Como se mencionó aquí , esas soluciones implican mostrar una diferencia combinada, como:
git diff --cc $M $M^1 $M^2 $(git merge-base $M^1 $M^2)
Pero: la salida de " diff --cc
" no mostraba las rutas originales cuando la fusión involucraba el cambio de nombre .
Una nueva opción en Git 2.22 (Q1 2019) agrega las rutas en los árboles originales a la salida.
git diff --cc --combined-all-paths $M $M^1 $M^2 $(git merge-base $M^1 $M^2)
log
,diff-tree
: agregue la--combined-all-paths
El formato de combinación de diferencias para las combinaciones solo incluirá un nombre de archivo, incluso si la detección de cambio de nombre o copia está activa.
Por ejemplo, con el formato en bruto uno podría ver:
::100644 100644 100644 fabadb8 cc95eb0 4866510 MM describe.c ::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM bar.sh ::100644 100644 100644 e07d6c5 9042e82 ee91881 RR phooey.c
Esto no nos permite saber cuál era el nombre original de
bar.sh
en el primer padre, y no nos permite saber cuál de los nombres originales dephooey.c
estaban en ninguno de los padres.En contraste, para las confirmaciones que no son de fusión, el formato en bruto proporciona nombres de archivos originales (y una puntuación de cambio de nombre para iniciar).
Para proporcionar también nombres de archivo originales para las combinaciones de combinación, agregue una--combined-all-paths
(que debe usarse con-c
o--cc
, y probablemente solo sea útil con el cambio de nombre o la detección de copia activa) para que podamos puede imprimir nombres de archivos separados por tabulaciones cuando se trata de renombrar.Esto transforma la salida anterior a:
::100644 100644 100644 fabadb8 cc95eb0 4866510 MM desc.c desc.c desc.c ::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM foo.sh bar.sh bar.sh ::100644 100644 100644 e07d6c5 9042e82 ee91881 RR fooey.c fuey.c phooey.c
Además, en formato de parche, esto cambia los encabezados de / a para que, en lugar de tener solo un encabezado "de", obtengamos uno para cada padre.
Por ejemplo, en lugar de tener
--- a/phooey.c +++ b/phooey.c
veríamos
--- a/fooey.c --- a/fuey.c +++ b/phooey.c
cuando tengo una confirmación de fusión y ejecuto git show #commit, solo muestra el registro de confirmación, no la diferencia del cambio real, como
commit c0f50178901e09a1237f7b9d9173ec5d1c4936c
Merge: ed234b ded051
Author: abc
Date: Mon Nov 21 15:56:33 2016 -0800
Merge branch ''abc''
Entiendo que la confirmación real está en el registro de combinación, pero quiero guardar la escritura, ¿hay alguna manera de mostrar el diff en uno?
TL; DR: use git show -m c05f017
o git show --first-parent c05f017
, o tal vez git diff c05f017^ c05f017
.
Hay un error fundamental en tu pregunta: los compromisos no son diferentes; Las confirmaciones son instantáneas. Esto podría parecer una distinción sin una diferencia, y para algunas confirmaciones, lo es . Pero para las combinaciones de mezcla, no lo es.
Cuando git show
(o git log -p
) muestra una confirmación como una diferencia, lo hace comparando la instantánea de la confirmación con otra cosa . El comando git diff
hace lo mismo: compara una confirmación con otra confirmación. (O puede comparar un compromiso con el árbol de trabajo, con el contenido del índice o con algunas otras combinaciones).
Para confirmaciones ordinarias, es trivialmente obvio qué comparar: compare la instantánea de esta confirmación con la instantánea de confirmación anterior (es decir, la principal). Así que eso es lo que hace git show
(y git log -p
también): ejecuta un git diff
desde la confirmación principal, hasta esta confirmación.
Sin embargo, los compromisos de combinación no tienen un solo compromiso principal. Tienen dos padres. 1 En primer lugar, esto es lo que los convierte en "combinaciones de combinaciones": la definición de una confirmación de combinación es una confirmación con al menos dos padres.
1 Un compromiso de fusión puede tener tres o más padres. Estos se llaman "fusiones de pulpo". Sin embargo, no hacen nada especial, y son principalmente para presumir. :-) Puedes ignorarlos aquí.
Cuando hay dos padres, ¿con cuál de ellos se debe comparar Git?
Lo que git log -p
elige hacer por defecto es no comparar en absoluto. Puedes hacer que muestre algo agregando varias banderas (ver más abajo).
Lo que git show
elige hacer por defecto es más complicado. Como hay dos padres, git show
primero se compara con el "primer padre", 2 luego se compara con el segundo padre. Entonces, esta parte es bastante crucial, combina las dos diferencias , produciendo una llamada "diferencia combinada".
Para la siguiente sección, permítanme notar un poco complicado, pero muy útil, de la sintaxis Git. Si tiene una ID de confirmación como c05f017
, puede agregar un carácter de caret o "hat" ^
después de eso, para nombrar una confirmación principal. Opcionalmente, puede agregar otro número para seleccionar qué padre. Para las confirmaciones regulares (no fusionadas) solo hay una, por lo que c05f017^
es el padre. Para las confirmaciones de mezcla, c05f017^
y c05f017^1
significan el primer padre , mientras que c05f017^2
significa el segundo padre .
2 Puse esto entre comillas porque la primera idea de los padres es especialmente importante en Git, como veremos en un momento. En otras palabras, a Git le importa más qué padre es el primero , mientras que el resto es solo "el resto".
Diferencias combinadas
El formato de diff combinado se describe en la documentación , pero here describe primero un bit clave, para que resulte especialmente oscuro: 3
Tenga en cuenta que las listas de diferencias combinadas solo son archivos que fueron modificados de todos los padres.
Es decir, supongamos que M es una confirmación de fusión, y la diferencia entre M ^ 1 y M dice que los archivos mainline.txt
y common.txt
se cambiaron. Supongamos además que las diferencias entre M ^ 2 y M dicen que el archivo common.txt
y common.txt
se cambiaron. El diff combinado mostrará solo common.txt
, omitiendo mainline.txt
y sidebranch.txt
porque esos dos archivos solo se modificaron de uno de los padres (cada uno). (Incluso entonces, Git puede mostrar solo algunas de las diferencias para common.txt
).
3 Me tomó mucho tiempo encontrar esto en la documentación, ya que seguía mirando la otra sección.
Dividiendo los diffs
La opción -m
probablemente significa fusionar aquí— le dice a Git que, en efecto, "divida" la fusión. Es decir, en lugar de tratar de combinar las diferencias contra cada padre en una gran diferencia combinada, simplemente muestre la diferencia contra cada padre, una diferencia a la vez.
Esto es a veces lo que quieres. Cuando no es lo que quieres, puedes ejecutar tu propio git diff
explícito para diferenciar solo contra uno de los dos padres (o ver más abajo).
¿Con qué padre o la madre deben diferenciar?
Por lo general, la respuesta correcta es "el primer padre".
La clave de la noción de "primer padre" es que cuando Git realiza una confirmación de fusión, siempre registra la rama en la que se encuentra en ese momento, como el primer padre. La otra rama se convierte en el segundo padre.
Es decir, si estás en develop
y fusionas el topic
:
$ git checkout develop
$ git merge topic
Git realizará un nuevo compromiso (un compromiso de combinación , con dos padres) en su rama actual, develop
. El primer padre de la confirmación de fusión será la confirmación que fue la punta de develop
hace un momento. El segundo padre será la confirmación que es (aún) la punta del topic
.
Ya que normalmente te preocupa lo que trajo la fusión, comparar eso con el primer padre te dará eso. Así que normalmente eso es lo que quieres. Por esta razón, git show
te permite ejecutar git show --first-parent
. Eso "divide" la confirmación y luego git show
solo diferencias contra el primer padre. (Esto es un poco diferente a git show -m
, que divide el compromiso dos veces: la primera división se compara con el primer padre, y la segunda división se compara con el segundo padre).
De manera similar, puede ejecutar git log -p --first-parent
... pero aún debe agregar -m
para ver el cambio como un parche, porque de forma predeterminada, el git log
solo omite mostrar las diferencias completamente para una combinación. (Internamente, la operación de omitir-porque-fusionar anula la forma en que la división hace que actúe como si no fuera una fusión). Aquí, el indicador --first-parent
tiene un efecto aún más importante: la operación de registro no se ve en ningún de las confirmaciones de la rama lateral, solo aquellas en la línea principal (primer padre).