2010-08-19 10 views
17

Entiendo bien cómo Git puede admitir movimientos de archivos: como utiliza el hash de archivos, un archivo "agregado" se detecta fácilmente como el mismo que "eliminado".¿Cómo rastrea Git el historial durante una refactorización?

Mi pregunta es acerca de la refactorización: considerando Java, la declaración del paquete cambia para que el contenido del archivo NO sea el mismo. En tal caso, ¿cómo determina Git que el archivo "agregado" comparte el historial con el "eliminado"? ¿Comprueba si hay "contenido más similar" suponiendo que solo realicé cambios menores o una solución no determinista similar?

+0

Espera un momento ... Eso "Apache Maven" libro justo en frente de mí tiene un nombre de autor inquietantemente familiar ... – VonC

+0

bien, estoy presente chico: D –

+0

¡Lo sabía! Todavía trato de olvidar la imagen de un Fred loco de "C'est pas sorcier" hablando sobre la migración de maven3 en un JUG reciente ... Buenos tiempos;) Bienvenido a SO. – VonC

Respuesta

20

Como se menciona en Git FAQ, detectará contenido similar basado en una heurística.

Git tiene que interoperar con una gran cantidad de flujos de trabajo diferentes, por ejemplo, algunos cambios pueden provenir de parches, donde la información de cambio de nombre puede no estar disponible. Confiar en el seguimiento de cambio de nombre explícito hace que sea imposible fusionar dos árboles que hayan hecho exactamente lo mismo, excepto que uno lo hizo como un parche (crear/eliminar) y uno lo hizo usando alguna otra heurística.

En una segunda nota, el seguimiento de los cambios de nombre es realmente solo un caso especial de seguimiento de cómo se mueve el contenido en el árbol. En algunos casos, puede estar interesado en consultar cuando se agregó una función o se movió a un archivo diferente. Al confiar únicamente en la capacidad de recrear esta información cuando sea necesario, Git tiene como objetivo proporcionar una forma más flexible de seguir cómo está cambiando su árbol.

Sin embargo, esto no significa que Git no tenga soporte para cambiar el nombre.
La maquinaria diff en Git tiene soporte para detectar automáticamente los cambios de nombre, esto se enciende mediante el interruptor '-M' a la familia de comandos git-diff-*.
git-log (1) y git-whatchanged (1) utilizan la maquinaria de detección de cambio de nombre, por ejemplo, 'git log -M' dará el historial de confirmación con la información de cambio de nombre.
Git también es compatible con una forma limitada de fusión entre cambios de nombre.
Las dos herramientas para asignar la culpa, git-blame(1) y git-annotate(1) usan el código de detección de cambio de nombre automático para rastrear los cambios de nombre.


git log le da algunos detalles sobre esa heurística:

-B[<n>][/<m>] 

rotura cambios completos de reescritura en pares de borrar y crear. Esto tiene dos propósitos:

  • Afecta a la forma en que un cambio que equivale a una reescritura total de un archivo no como una serie de eliminación e inserción mezclados con muy pocas líneas que pasan a coincidir textualmente como el contexto , pero como una sola eliminación de todo lo antiguo seguido de una sola inserción de todo lo nuevo, y el número m controla este aspecto de la opción -B (por defecto es 60%).
    -B/70% especifica que menos del 30% del original debe permanecer en el resultado para que git lo considere una reescritura total (es decir, el parche resultante será una serie de eliminación e inserción mezclada con líneas de contexto)

  • Cuando se usa con -M, un archivo totalmente reescrito también se considera como la fuente de un cambio de nombre (generalmente -M solo considera un archivo que desapareció como origen de un cambio de nombre), y el número n controla este aspecto de la opción -B (predeterminado en 50%).
    -B20% especifica que un cambio con adición y eliminación en comparación con el 20% o más del tamaño del archivo son elegibles para ser recogidos como una posible fuente de cambio de nombre a otro archivo.

-M[<n>] 

Si la generación de diferenciaciones, detectar y reportar cambia el nombre de cada confirmación. Para los siguientes archivos a través del cambio de nombre mientras se recorre el historial, vea --follow.
Si se especifica n, a es un umbral en el índice de similitud (es decir, cantidad de adiciones/eliminaciones en comparación con el tamaño del archivo).
Por ejemplo, -M90% significa que git debería considerar un par de eliminar/agregar para cambiar el nombre si más del 90% del archivo no ha cambiado.


referencias adicionales:

+0

OK, pero ¿hay una respuesta simple en lenguaje sencillo a la situación original? Si refactorizo ​​una clase de Java moviéndola a un directorio de paquetes diferente, de modo que de (por ejemplo) 100 líneas se modifique una sola línea que indique el paquete de Java, ¿registrarán _default_ y culparán el movimiento/cambio de nombre? ¿Seguiré viendo la culpa correcta en GitHub/BitBucket? En otras palabras, ¿las cosas "solo funcionarán" con la configuración predeterminada de todo si realizo esta (muy, muy, muy) actividad común? –

+0

@GarretWilson sí, lo hará en el lado local (donde puede invocar 'git log --follow' (como en http://stackoverflow.com/q/2314652/6309) o' git culpa '-. Esto ganó Sin embargo, se hará en el servidor Git (GitHub: http://stackoverflow.com/a/5647721/6309) (o BitBucket: https://bitbucket.org/site/master/issues/589/file- history-should-follow-copies-and) – VonC

+0

Gracias por la rápida aclaración con los enlaces! Voy a retener mis comentarios sobre Git, que parece que no tengo más remedio que usar ... :) –

Cuestiones relacionadas