¿Cómo grep Git commit diffs o contenidos para una palabra determinada?

623

En un repositorio de código Git, quiero enumerar todas las confirmaciones que contienen una palabra determinada. Probé esto

git log -p | grep --context=4 "word"

pero no necesariamente me devuelve el nombre de archivo (a menos que esté a menos de 5 líneas de la palabra que busqué. También intenté

git grep "word"

pero solo me da archivos actuales y no el historial.

¿Cómo busco en todo el historial para poder seguir los cambios en una palabra en particular? Tengo la intención de buscar en mi base de código las apariciones de palabras para rastrear los cambios (buscar en el historial de archivos).

Jesper Rønn-Jensen
fuente

Respuestas:

907

Si quieres encontrar todos los commits donde mensaje de confirmación contiene una palabra dada, use

$ git log --grep=word

Si desea encontrar todas las confirmaciones donde se agregó o eliminó "palabra" en el contenido del archivo (para ser más exactos: dónde cambió el número de ocurrencias de "palabra"), es decir, busque el contenido commit , use la llamada búsqueda 'pickaxe' con

$ git log -Sword

En git moderno también hay

$ git log -Gword

buscar diferencias cuya línea agregada o eliminada coincida con "palabra" (también confirmar contenido ).

Tenga en cuenta que, -Gde forma predeterminada, acepta una expresión regular, mientras que -Sacepta una cadena, pero puede modificarse para aceptar expresiones regulares utilizando--pickaxe-regex .

Para ilustrar la diferencia entre -S<regex> --pickaxe-regexy -G<regex>, considere una confirmación con la siguiente diferencia en el mismo archivo:

+    return !regexec(regexp, two->ptr, 1, &regmatch, 0);
...
-    hit = !regexec(regexp, mf2.ptr, 1, &regmatch, 0);

Mientras git log -G"regexec\(regexp"mostrará esta confirmación, git log -S"regexec\(regexp" --pickaxe-regexno lo hará (porque el número de apariciones de esa cadena no cambió).


Con Git 2.25.1 (febrero de 2020), la documentación se aclara en torno a esas expresiones regulares.

Ver commit 9299f84 (06 de febrero de 2020) por Martin Ågren (``) .
(Fusionada por Junio ​​C Hamano - gitster- en commit 0d11410 , 12 de febrero de 2020)

diff-options.txt: evite la sobrecarga "regex" en el ejemplo

Reportado por: Adam Dinwoodie
Firmado por: Martin Ågren
Revisado por: Taylor Blau

Cuando ejemplificamos la diferencia entre -Gy -S(usando --pickaxe-regex), lo hacemos usando un ejemplo diff ygit diff invocación que involucra "regexec", "regexp", "regmatch", ...

El ejemplo es correcto, pero podemos hacer que sea más fácil desenredar evitando escribir "regex. *" A menos que sea realmente necesario para aclarar nuestro punto.

Utilice algunas palabras inventadas, no regexy en su lugar.

La git diffdocumentación ahora incluye:

Para ilustrar la diferencia entre -S<regex> --pickaxe-regexy -G<regex>, considere una confirmación con la siguiente diferencia en el mismo archivo:

+    return frotz(nitfol, two->ptr, 1, 0);
...
-    hit = frotz(nitfol, mf2.ptr, 1, 0);

Mientras git log -G"frotz\(nitfol"mostrará esta confirmación, git log -S"frotz\(nitfol" --pickaxe-regexno lo hará (porque el número de apariciones de esa cadena no cambió).

Jakub Narębski
fuente
3
@TankorSmash -S<string>Busque diferencias que introducen o eliminan una instancia de <string>. -G<string>Busque diferencias cuya línea agregada o eliminada coincida con la <regex> dada.
m-ric
1
@ m-ric ¡Oh, ya veo, una sola instancia de cadena, frente a una línea completa! Gracias
TankorSmash
3
@ m-ric, @TankorSmash: La diferencia es que -S<string>es más rápido porque solo verifica si el número de ocurrencias ha <string>cambiado, mientras que las -G<string>búsquedas agregan y eliminan líneas en cada confirmación de confirmación.
Jakub Narębski
3
Si necesita buscar palabras con espacio en el medio git log --grep="my words",.
MEM
44
@MEM, --grepes diferente de -Sy -G. Puede citar la cadena a cada uno de estos argumentos.
Acumenus
255

git logLa piqueta encontrará confirmaciones con cambios que incluyen "word" con git log -Sword

u0b34a0f6ae
fuente
6060
Esto no es del todo preciso. -S <cadena> Busque diferencias que introducen o eliminan una instancia de <cadena>. Tenga en cuenta que esto es diferente a la cadena que simplemente aparece en la salida diff;
tymtam
44
Si bien esta es generalmente la respuesta correcta, voté en contra solo para alentar a otros a leer esta respuesta ( stackoverflow.com/a/1340245/586983 ) que tiene 3 formas diferentes y explica sus sutilezas.
jakeonrails
18
¡Dios mio! No creo que sea una buena razón para rechazar una respuesta correcta ... ¿no estaba seguro de que incluir el enlace en un comentario sería suficiente estímulo?
Deborah
@jakeonrails, esa respuesta debería haber sido una edición de esta (más antigua), por lo que no tenemos estos molestos duplicados. Pero la gente solo quiere la reputación, en lugar de una página de respuestas limpias.
Iulian Onofrei
22

Después de mucha experimentación, puedo recomendar lo siguiente, que muestra confirmaciones que introducen o eliminan líneas que contienen una expresión regular dada, y muestra los cambios de texto en cada una, con colores que muestran palabras agregadas y eliminadas.

git log --pickaxe-regex -p --color-words -S "<regexp to search for>"

Sin embargo, lleva un tiempo correr ... ;-)

CharlesW
fuente
2
Este es uno de los mejores hasta ahora, gracias. Sugerencia: para enumerar todos los resultados sin paginación, anteponga el comando GIT_PAGER=cato añádalo con| cat
Zack Morris
Especificar una ruta o archivo sería mucho más rápidogit log --pickaxe-regex -p --color-words -S "<regexp to search for>" <file or fiepath>
Fangxing
10

Puedes probar el siguiente comando:

git log --patch --color=always | less +/searching_string

o usando grepde la siguiente manera:

git rev-list --all | GIT_PAGER=cat xargs git grep 'search_string'

Ejecute este comando en el directorio principal donde desea buscar.

kenorb
fuente
2
Me gusta este método porque los commits que estoy viendo tienen cientos de líneas de cambios no relacionados, y solo estoy interesado en los parches reales que involucran la palabra que estoy buscando. Para obtener el color de uso git log --patch --color=always | less +/searching_string.
Radon Rosborough
9

Una forma / sintaxis más para hacerlo es: git log -S "word"
así, puede buscar, por ejemplogit log -S "with whitespaces and stuff @/#ü !"

1u-
fuente
1

Para usar el conector booleano en expresiones regulares:

git log --grep '[0-9]*\|[a-z]*'

Esta expresión regular busca la expresión regular [0-9] * o [az] * en los mensajes de confirmación.

Reudismo
fuente
-1

Si desea buscar datos confidenciales para eliminarlos de su historial de git (que es la razón por la que aterricé aquí), existen herramientas para eso. Github como una página de ayuda dedicada para ese problema .

Aquí está la esencia del artículo:

El BFG Repo-Cleaner es una alternativa más rápida y simple a git filter-branch para eliminar datos no deseados. Por ejemplo, para eliminar su archivo con datos confidenciales y dejar intacto su último commit), ejecute:

bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

Para reemplazar todo el texto listado en passwords.txt donde sea que se encuentre en el historial de su repositorio, ejecute:

bfg --replace-text passwords.txt

Consulte la documentación del BFG Repo-Cleaner para conocer el uso completo y las instrucciones de descarga.

Edelans
fuente
Es posible que desee agregar esta respuesta a stackoverflow.com/questions/872565/… en lugar de aquí
lacostenycoder