2011-01-24 8 views
61

Así que encontré la pregunta sobre cómo ver el historial de cambios de un archivo, pero el historial de cambios de este archivo en particular es enorme y en realidad solo me interesan los cambios de un método en particular. Entonces, ¿sería posible ver el historial de cambios solo para ese método en particular?Git: ¿cómo veo el historial de cambios de un método/función?

Sé que esto requeriría que git analice el código y que el análisis sería diferente para diferentes idiomas, pero las declaraciones de método/función son muy similares en la mayoría de los lenguajes, así que pensé que quizás alguien había implementado esta característica.

El lenguaje con el que estoy trabajando actualmente es Objective-C y el SCM que estoy usando actualmente es git, pero me gustaría saber si esta característica existe para cualquier SCM/idioma.

+1

He visto tal funcionalidad en la propuesta de Git GSoG. –

+0

¿Es esta la propuesta de la que hablabas? http://lists-archives.org/git/715169-gsoc-draft-proposal-line-level-history-browser.html –

+1

posible duplicado de [Recuperar el registro de confirmación para una línea específica en un archivo?] (http: //stackoverflow.com/questions/8435343/retrieve-the-commit-log-for-a-specific-line-in-a-file) – lpapp

Respuesta

2

git blame muestra quién cambió por última vez cada línea del archivo; puede especificar las líneas para examinar a fin de evitar obtener el historial de líneas fuera de su función.

+0

Solo muestra la última revisión, aunque ... – poke

+4

con 'git gui culpa' puede navegar revisiones anteriores. –

8

git log tiene una opción '-G' podría utilizarse para encontrar todas las diferencias.

Look -G las diferencias cuyas añadido o eliminado la línea coincide con la dada <regex>.

Simplemente proporciónele una expresión correcta del nombre de la función que le interese. Por ejemplo,

$ git log --oneline -G'^int commit_tree' 
40d52ff make commit_tree a library function 
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory 
7b9c0a6 git-commit-tree: make it usable from other builtins 
+4

No ejecuté el comando, pero me parece que este comando solo mostraría las confirmaciones que tocan la línea que coincide con la expresión regular, que no es el método/función completo. –

+0

si quiere más contexto, puede reemplazar '--oneline' con' -p' – lfender6445

+2

¿Pero qué pasa si se hacen 20 líneas en el método? – nafg

13

Usando git gui blame es difícil de hacer uso de secuencias de comandos, y mientras git log -G y git log --pickaxe cada uno puede mostrar que cuando la definición del método apareció o desapareció, no he encontrado ninguna manera de hacer la lista de todos cambios realizados en el cuerpo de su método.

Sin embargo, puede usar gitattributes y la propiedad textconv para armar una solución que hace precisamente eso. Aunque estas funciones fueron originalmente diseñadas para ayudarlo a trabajar con archivos binarios, funcionan igual de bien aquí.

La clave es hacer que Git elimine del archivo todas las líneas excepto las que le interesan antes de realizar cualquier operación de diferenciación. Luego, git log, git diff, etc. solo verá el área que le interese.

Aquí está el resumen de lo que hago en otro idioma; puedes ajustarlo para tus propias necesidades.

  • escribir un guión corto cáscara (u otro programa) que toma un argumento - el nombre de un archivo de origen - y salidas sólo la parte interesante de ese archivo (o nada si nada de esto es interesante) . Por ejemplo, es posible utilizar sed de la siguiente manera:

    #!/bin/sh 
    sed -n -e '/^int my_func(/,/^}/ p' "$1" 
    
  • definir un filtro Git textconv para su nuevo guión. (Consulte la página del manual gitattributes para obtener más detalles.) El nombre del filtro y la ubicación del comando pueden ser lo que desee.

    $ git config diff.my_filter.textconv /path/to/my_script 
    
  • Dile Git para utilizar ese filtro antes de calcular diffs para el archivo en cuestión.

    $ echo "my_file diff=my_filter" >> .gitattributes 
    
  • Ahora, si se utiliza -G. (nótese el .) para enumerar todas las confirmaciones que producen cambios visibles cuando se aplica el filtro, tendrá exactamente esas confirmaciones que le interesan. Cualquier otra opción que usan rutinas diff de Git, como --patch, también obtendrán esta vista restringida.

    $ git log -G. --patch my_file 
    
  • Voilà!

Una mejora útil es posible que desee hacer es tener la secuencia de comandos de filtro toma un nombre de método como primer argumento (y el archivo como su segundo). Esto le permite especificar un nuevo método de interés simplemente llamando al git config, en lugar de tener que editar su secuencia de comandos. Por ejemplo, usted podría decir:

$ git config diff.my_filter.textconv "/path/to/my_command other_func" 

Por supuesto, el guión de filtro puede hacer lo que quiera, tome más argumentos, o lo que sea: hay una gran cantidad de flexibilidad más allá de lo que he mostrado aquí.

+1

La toma de más de un argumento no funcionó para mí, pero poner el nombre de la función en hard funciona bien y ¡esto es realmente increíble! – qwertzguy

+0

Brillante, aunque me pregunto cómo (en) es conveniente cambiar entre muchos métodos diferentes. Además, ¿conoce algún programa que pueda sacar una función completa tipo C? – nafg

7

Lo más parecido que puede hacer es determinar la posición de su función en el archivo (por ejemplo, supongamos que su función es i_am_buggy en las líneas 241-263 de foo/bar.c), a continuación, ejecute algo en el sentido de:

git log -p -L 200,300:foo/bar.c 

Esto abrirá menos (o un buscapersonas equivalente). Ahora puede escribir en /i_am_buggy (o su equivalente en buscapersonas) y comenzar a revisar los cambios.

Esto podría incluso trabajar, dependiendo de su estilo de código:

git log -p -L /int i_am_buggy\(/,+30:foo/bar.c 

Esto limita la búsqueda desde el primer golpe de esa expresión regular (lo ideal es que su declaración de la función) a treinta líneas después de eso. El argumento final también puede ser una expresión regular, aunque la detección de que con expresiones regulares es una proposición de iffier.

+0

¡Dulce! Para su información, esto es nuevo en Git v1.8.4. (Supongo que debería actualizar). Sin embargo, una solución más precisa sería agradable ... como si alguien escribiera la respuesta de Paul Whittaker. –

+0

@GregPrice [Aparentemente los bordes de la búsqueda pueden ser expresiones regulares] (http://git-scm.com/docs/git-log), por lo que al menos puede tener un punto de inicio más o menos preciso. – badp

+0

Oh, wow. De hecho: en lugar de escribir su propia expresión regular, puede decir '-L": int myfunc: foo/bar.c "' y limitar a la función con ese nombre. Esto es fantástico, ¡gracias por el puntero! Ahora, si solo la detección de función fuera un poco más confiable ... –

41

Las versiones recientes de git log aprendieron una forma especial del parámetro -L:

-L: < funcname>: < archivo>

traza la evolución de la gama de línea dada por "<start>,<end>" (o el nombre de la función regex <funcname>) dentro del <file>. No puedes dar ningún limitador de pathspec. Esto se limita actualmente a una caminata a partir de una única revisión, es decir, solo puede dar cero o un argumento de revisión positivo. Puede especificar esta opción más de una vez.
...
Si “:<funcname>” se da en lugar de <start> y <end>, que es una expresión regular que denota el rango de la primera línea funcname que coincide con <funcname>, hasta la siguiente línea funcname. “:<funcname>” busca desde el final del rango -L anterior, si lo hubiera, de lo contrario desde el principio del archivo. “^:<funcname>” busca desde el inicio del archivo.

En otras palabras: si le preguntas a Git git log -L :myfunction:path/to/myfile.c, se imprimirá ahora felizmente el historial de cambios de esa función.

+4

esto puede funcionar para objetivo-c de fábrica, pero si lo hace para otros idiomas (p. Ej., Python, Ruby, etc.) es posible que necesite agregar el apropiado configuración dentro de un archivo .gitattributes para que git reconozca las declaraciones de función/método en ese idioma. Para Python use * .py diff = python, para ruby ​​use * .rb diff = ruby ​​ – samaspin

+0

¿Cómo rastrea git la función? – nn0p

+0

@ nn0p Supongo que al tener un conocimiento sintáctico de varios idiomas y saber cómo aislar una función y rastrear sus cambios. – JasonGenX

Cuestiones relacionadas