Comparando diferencias en una rebase en Git

Supongamos que acabo de volver a establecer la twig foo en master , con conflictos. Quiero asegurarme de no dañar accidentalmente el contenido de foo durante la resolución de conflictos introduciendo cambios adicionales o perdiendo cambios (que no sean los apropiados para la resolución del conflicto). Lo he hecho a través de:

 diff -u <(git diff `git merge-base master foo@{1}` foo@{1}) \ <(git diff `git merge-base master foo ` foo ) 

(actualización: o la syntax equivalente para git-diff que me acaban de recordar 🙂

 diff -u <(git diff master...foo@{1}) <(git diff master...foo) | mate 

Esto me muestra todos los cambios que se le han ocurrido al master..foo considerado como un parche , que es exactamente lo que quiero verificar por ser mínimo. Sin embargo, la invocación es compleja y el resultado no es completamente sencillo de interpretar.

¿Hay una mejor manera de lograr esta tarea? ¿Proporcionar la misma información, pero con un mejor método o formatting? ¿O debería simplemente tomar lo anterior y finalizarlo en un script?

Lo que realmente queremos mostrar es el conflicto de diff combinado que se genera como si hubiéramos hecho una combinación para get de (a) a (b) donde (a) se basó previamente (en sentido ascendente) y (b) es ahora basado en (upstream-new).

No queremos solo una diferencia directa.

En cambio, básicamente podemos hacer la fusión pero forzar que el tree resultante sea $ b ^ {tree}, que ya sabemos que es el punto "final" correcto de lo que queremos.

Más o less, supongamos que tenemos

 newcommit -> the new version of the series oldcommit -> the old version of the series upstream -> the (new) version of the base of the series 

Podemos generar la fusión a través de

 git commit-tree newcommit^{tree} -p oldcommit -p upstream -m "message" 

y luego muestre el resultado con "git show" y esto generará un formatting de diferencias combinado que muestra todos los bits necesarios como una resolución de conflicto que ignora automáticamente los cambios que no fueron parte de la resolución de conflictos.

Esto incluso funciona simplemente para mejorar un cambio, y puede hacer un poco más de trabajo para asegurarse de que la confirmación de fusión generada tenga autor exacto y confirme las marcas de time para que sea consistente en varias llamadas (ya que estamos almacenando una reference suelta en el object database).

Desafortunadamente, no he podido descifrar cómo hacer que "git diff" difiera de la misma forma sin generar un tree todavía. No estoy seguro de qué arguments tendríamos que pasar para llegar a ese punto.

Diferencias entre el maestro y el foo rebasado:

git diff master..foo

vs.

Diferencias de foo antes de la rebase después de la bifurcación del maestro (observe tres puntos):

git diff master...foo@{1}

?

Dado que es una database y no una combinación, es posible que desee comparar foo consigo mismo, pero antes de la fusión. Si recuerdo correctamente, foo@{1} producirá el padre del compromiso actual para foo , y tal vez esto no sea lo que está buscando.

Creo que puedes hacer algo como lo siguiente (suponiendo que no hayas hecho un git gc ):

En la twig foo después de la rebase:

 $ git reflog 

Esto mostrará cómo se ha movido la CABEZA de su twig. Debería ver algunos loggings como este (dependiendo de si tiene una base interactiva o no):

 64d3c9e HEAD@{15}: rebase -i (finish): returning to refs/heads/master 64d3c9e HEAD@{16}: rebase -i (fixup): Fixes external dependencies 049169e HEAD@{17}: rebase -i (fixup): updating HEAD d4c2e69 HEAD@{18}: rebase -i (pick): Fixes external dependencies 049169e HEAD@{19}: rebase -i (fixup): Imports futures e490bed HEAD@{20}: rebase -i (fixup): updating HEAD ... etc ... 

Esperamos el último commit de foo antes de la fusión. Dependiendo de lo que hayas hecho, puede ser difícil o no. Es por eso que no he proporcionado un script do-it.

Recoja el ID de confirmación que tiene el último commit para foo antes de la rebase y luego compare con ese ID de confirmación. Diga que la identificación de confirmación es: XXXX :

  git diff XXXX...foo 

Tal vez eso es lo que quieres.

git-cherry busca commits en una twig que no están en otra. Lo usarías como:

 git cherry -v OLDTIP TIP UPSTREAM 

es decir, busca confirmaciones que estaban en OLDTIP pero que no están en UPSTREAM..TIP . Mira la firma del parche para ver si se incluye un parche, por lo que si se agregó un parche, se descartó o se modificó durante la rebase, aparecerá en la list. Las cosas que se aplicaron sin cambios no aparecerán.

Se puede lograr un efecto similar volviendo a OLDTIP y haciendo git rebase -i TIP , ya que usa la misma lógica para completar la list de confirmaciones.

Un enfoque ligeramente diferente: Git tiene un buen soporte para mostrar esto en el caso de fusiones. es decir, "¿qué cambió en relación con el padre-1 que no puede ser explicado por el padre-2?"

Hay un par de forms en que puede aprovechar ese soporte para su rebase:

Opción 1:

  1. Primero realice una fusión desechable (en lugar de una rebase). Luego, la pantalla de fusión normal mostrará qué cambió. Comtesting que esto es lo que querías.

  2. Regrese y vuelva a calcular, y compare la sugerencia rebasada con el resultado de la fusión: deben ser idénticos.

Opción 2 (si rebase es más fácil que fusionar):

  1. Haz la rebase
  2. Use un injerto para que parezca una fusión local / temporal.

Para hacer eso, crea un .git / info / injertos con una sola línea:

 TIP UPSTREAM OLDTIP 

Donde TIP es la identificación de compromiso de su twig networkingefinida y los otros son los dos padres deseados (es decir, las dos cosas que habría fusionado, si hubiera estado fusionándose). Luego examínelo como si fuera una fusión real.

No estoy seguro de poder automatizarlo; Tiendo a hacer esto con gitk abierto, porque hace que la comparación de las revisiones correctas sea fácil (usando el menu contextual).

Si realmente quiere comparar dos diffs, entonces puede que quiera ver interdiff (1), pero no estoy seguro de qué tan bien hará frente a que los files base sean diferentes.