¿Cómo grep confirmaciones basadas en una determinada cadena?

9 minutos de lectura

Avatar de usuario de Jesper Rønn-Jensen
Jesper Ronn-Jensen

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

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

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

git grep "word"

pero solo me da archivos actuales y no la historia.

¿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 apariciones de palabras para rastrear cambios (buscar en el historial de archivos).

  • ¿Posible duplicado de How to grep (buscar) código comprometido en el historial de git?

    –Ortwin Gentz

    5 de junio de 2018 a las 16:02

Avatar de usuario de Jakub Narębski
Jakub Narębski

Si desea encontrar todas las confirmaciones en las que mensaje de compromiso 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: donde cambió el número de ocurrencias de “palabra”), es decir, buscar el confirmar contenidouse 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 coincide con “palabra” (también confirmar contenidos).

Algunas cosas a tener en cuenta:

  • -G por defecto acepta una expresión regular, mientras que -S acepta una cadena, pero se puede modificar para aceptar expresiones regulares usando el --pickaxe-regex.
  • -S encuentra confirmaciones donde cambió el número de ocurrencias de “palabra”, mientras que -G encuentra confirmaciones donde aparece “palabra” en la diferencia.
  • Esto significa que -S<regex> --pickaxe-regex y -G<regex> no hagas exactamente lo mismo.

El git diff documentación tiene una buena explicación de la diferencia:

Para ilustrar la diferencia entre -S<regex> --pickaxe-regex y -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á este compromiso, git log -S"frotz\(nitfol" --pickaxe-regex no lo hará (porque el número de ocurrencias de esa cadena no cambió).

Esto mostrará las confirmaciones que contienen los términos de búsqueda, pero si desea ver los cambios reales en esas confirmaciones, puede usar --patch:

$ git log -G"searchTerm" --patch

Esto puede entonces ser canalizado a grep para aislar la salida solo para mostrar líneas de confirmación de diferencia con ese término de búsqueda. Un caso de uso común es mostrar líneas de diferencias con ese término de búsqueda en confirmaciones desde e incluyendo una confirmación determinada: 3b5ab0f2a1 en este ejemplo – así:

$ git log 3b5ab0f2a1^.. -G"searchTerm" --patch | grep searchTerm

  • @TankorSmash -S<string> Busque diferencias que introduzcan o eliminen una instancia de . -G<string> Busque diferencias cuya línea agregada o eliminada coincida con la dada.

    – m-ric

    4 de noviembre de 2013 a las 20:19


  • @m-ric Oh, ya veo, ¡una instancia de una sola cadena, frente a una línea completa! Gracias

    – TankorSmash

    4 de noviembre de 2013 a las 20:35

  • @m-ric, @TankorSmash: La diferencia es que -S<string> es más rápido porque solo verifica si el número de ocurrencias de <string> cambiado, mientras -G<string> busca líneas añadidas y eliminadas en cada diferencia de confirmación.

    – Jakub Narębski

    5 de noviembre de 2013 a las 17:18

  • Si necesita buscar palabras con espacios en medio,git log --grep="my words".

    – MEM

    21 de mayo de 2014 a las 12:45

  • @MEM, --grep es diferente de -S y -G. Puede citar la cadena para cada uno de estos argumentos.

    – Asclepio

    12/08/2014 a las 20:33

avatar de usuario de u0b34a0f6ae
u0b34a0f6ae

git logEl pico de encontrará confirmaciones con cambios que incluyen “palabra” con git log -Sword

  • Esto no es del todo preciso. -S Busque diferencias que introduzcan o eliminen una instancia de . Tenga en cuenta que esto es diferente a la cadena que simplemente aparece en la salida diff;

    – tymtam

    11 de agosto de 2011 a las 2:34


  • Si bien esta es generalmente la respuesta correcta, voté a la baja solo para alentar a otros a leer esta respuesta (stackoverflow.com/a/1340245/586983) que tiene 3 formas diferentes y explica sus sutilezas.

    – jakeonrails

    7 de enero de 2016 a las 19:18

  • ¡Dios mio! No creo que sea una buena razón para rechazar una respuesta correcta… ¿no estabas seguro de que incluir el enlace en un comentario sería suficiente estímulo?

    – Débora

    24 de junio de 2016 a las 4:53

  • @jakeonrails, esa respuesta debería haber sido una edición de esta (más antigua), para que no tengamos estos molestos duplicados. Pero la gente solo quiere la reputación, en lugar de una página de respuestas limpia.

    – Iulian Onofrei

    6 de febrero de 2018 a las 14:56

  • Ejemplos de culpar a las personas en lugar del sistema. Stack Overflow debería tener formas más variadas y matizadas de: desviar la atención, recompensar la mejora, calificar y cuantificar, exaltar la esencia, aclarar y profundizar. Y para divagar sin desmerecer, guiño guiño guiño.

    –Bob Stein

    22 de enero de 2022 a las 17:56

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 las palabras agregadas y eliminadas.

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

Sin embargo, tarda un poco en ejecutarse… 😉

  • Este es uno de los mejores hasta ahora gracias. Sugerencia: para enumerar todos los resultados sin paginación, anteponga el comando con GIT_PAGER=cat o añádelo con | cat

    – Zack Morris

    17/09/2018 a las 19:58

  • Especificar una ruta o un archivo sería mucho más rápido git log --pickaxe-regex -p --color-words -S "<regexp to search for>" <file or fiepath>

    – colmillo

    26 de septiembre de 2019 a las 7:56

  • ¿Se puede modificar esto para mostrar solo las líneas que coinciden con el patrón, en lugar de la diferencia completa? (Encontré la respuesta aquí: stackoverflow.com/a/51603771/1231241)

    – Dannid

    29 de enero de 2021 a las 17:03


  • Puede agregar un límite a la salida para evitar que se salga de control: git log -n 1000 --pickaxe-regex -p --color-words -S "<regexp to search for>"

    – Automático

    30 de noviembre de 2021 a las 12:04


Una forma/sintaxis más para hacerlo es: git log -S "word"

Así puedes buscar por ejemplo git log -S "with whitespaces and stuff @/#ü !"

avatar de usuario de kenorb
kenorb

Puedes probar el siguiente comando:

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

o usando grep de la siguiente manera:

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

Ejecute este comando en el directorio principal donde le gustaría buscar.

  • Me gusta este método porque las confirmaciones 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 uso de color git log --patch --color=always | less +/searching_string.

    – Radón Rosborough

    16/10/2016 a las 19:17


  • Para encontrar algo en las confirmaciones de basura, use: git fsck | grep -Po '(?<=commit ).*' | GIT_PAGER xargs git grep 'search_string'

    – galvá

    12 de noviembre de 2020 a las 10:15


Avatar de usuario de Peter Mortensen
Pedro Mortensen

Para usar un conector booleano en una expresión regular:

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

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

  • Me gusta este método porque las confirmaciones 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 uso de color git log --patch --color=always | less +/searching_string.

    – Radón Rosborough

    16/10/2016 a las 19:17


  • Para encontrar algo en las confirmaciones de basura, use: git fsck | grep -Po '(?<=commit ).*' | GIT_PAGER xargs git grep 'search_string'

    – galvá

    12 de noviembre de 2020 a las 10:15


Avatar de usuario de Peter Mortensen
Pedro Mortensen

Esto es útil en combinación con BFG (Rama de filtro de Git: no debe confundirse con git-filter-branch) y git-filter-repo. Simplemente obtiene las rutas de los archivos para que pueda ingresarlos en una de las dos herramientas que acabo de mencionar.

A. Rutas relativas, únicas, ordenadas:

# Get all unique filepaths of files matching 'password'
# Source: https://stackoverflow.com/a/69714869/10830091
git rev-list --all | (
    while read revision; do
        git grep -F --files-with-matches 'password' $revision | cat | sed "s/[^:]*://"
    done
) | sort | uniq

B. Nombres de archivo únicos, ordenados (no rutas):

# Get all unique filenames matching 'password'
# Source: https://stackoverflow.com/a/69714869/10830091
git rev-list --all | (
    while read revision; do
        git grep -F --files-with-matches 'password' $revision | cat | sed "s/[^:]*://"
    done
) | xargs basename | sort | uniq

Este segundo comando es útil para BFG, porque solo acepta nombres de archivo y no rutas relativas al repositorio/absolutas del sistema.

Ahí tienes Disfrute usando estos fragmentos de Bash por tanta agonía como me causaron a mí. Odio a Bash, entonces, ¿por qué sigo usándolo?

Disección

Obtener solo nombres de archivo/rutas

Cualquiera de las siguientes opciones significa lo mismo (documentación de git-rep):

  • -l
  • --files-with-matches
  • --name-only

En lugar de mostrar todas las líneas coincidentes, muestre solo los nombres de los archivos que contienen Blockquote

¿Es su patrón: A. Regex vs B. Fixed String?

Como para -Fbueno, solo significa usar una cadena fija en lugar de una expresión regular para la interpretación de patrones. Una fuente.

Otra nota útil que pertenece aquí: puede agregar -i o --ignore-case ser mayúsculas y minúsculas.

Deshazte de ese estúpido hash de confirmación principal

sed "s/[^:]*://"

Fuente.

¡Consígueles caminos únicos!

| sort | uniq

¿Quién quiere caminos duplicados? ¡Tú no, yo no! ¡Oh, mira, también están ordenados! Disfrutar.

Fuente: yo. He usado esto desde que tengo memoria. (man sort y man uniq)

¿Qué pasa con los nombres de archivo sin rutas?

xargs basename

Tu pensarias | basename funcionaría, pero no. No acepta entrada entrada estándar, pero como argumentos de línea de comando. Aquí está una explicación para eso. ¡Imagínate! basename básicamente devuelve el nombre de archivo principal sin su ruta principal. man basename.

Para el método A., quiero rutas absolutas, no relativas.

Claro, solo dale una palmada realpath al final. Al igual que:

) | sort | uniq | xargs realpath

Por supuesto que tienes que usar xargs porque realpath no utiliza la entrada estándar para la entrada. Utiliza argumentos de línea de comandos. Al igual que dirname.

inspiraciones

  • Echa un vistazo a esta increíble respuesta alternativa.
  • Buscar en todo el historial de Git una cadena
  • Nombres de archivo solo usando Git grep

  • ¡Gracias por las ediciones @Peter Mortensen! Mi respuesta se ve aún más nítida ahora, con estos errores tipográficos y las URL desnudas corregidas. Sus descripciones de edición también son acertadas, ya que me ayudan a evitar repetir esos problemas corregidos.

    – om-ja

    29 de noviembre de 2021 a las 10:36


¿Ha sido útil esta solución?