¿Cómo buscar en todas las confirmaciones de Git y Mercurial en el repositorio una determinada cadena?

287

Tengo un repositorio Git con pocas ramas y confirmaciones colgantes. Me gustaría buscar todas estas confirmaciones en el repositorio para una cadena específica.

Sé cómo obtener un registro de todas las confirmaciones en el historial, pero estas no incluyen ramas o blobs colgantes, solo el historial de HEAD. Quiero obtenerlos a todos, para encontrar un compromiso específico que se extravió.

También me gustaría saber cómo hacer esto en Mercurial, ya que estoy considerando el cambio.

Josip
fuente

Respuestas:

331

Puedes ver confirmaciones colgantes con git log -g.

-g, --walk-reflogs
 Instead of walking the commit ancestry chain, walk reflog entries from
 the most recent one to older ones. 

Entonces, puede hacer esto para encontrar una cadena particular en un mensaje de confirmación que cuelga:

git log -g --grep=search_for_this

Alternativamente, si desea buscar los cambios para una cadena en particular, puede usar la opción de búsqueda de pico, "-S":

git log -g -Ssearch_for_this
# this also works but may be slower, it only shows text-added results
git grep search_for_this $(git log -g --pretty=format:%h)

Git 1.7.4 agregará la opción -G , permitiéndole pasar -G <regexp> para encontrar cuándo se movió una línea que contiene <regexp>, lo que -S no puede hacer. -S solo le indicará cuándo cambió el número total de líneas que contienen la cadena (es decir, agregar / quitar la cadena).

Finalmente, puede usar gitk para visualizar las confirmaciones colgantes con:

gitk --all $(git log -g --pretty=format:%h)

Y luego use sus funciones de búsqueda para buscar el archivo fuera de lugar. Todo este trabajo suponiendo que el commit faltante no ha "caducado" y se ha recolectado basura, lo que puede suceder si está colgando durante 30 días y expira los registros o ejecuta un comando que caduca.

richq
fuente
44
Quizás en lugar de ejecutar "git grep" en un número (posiblemente grande) de confirmaciones, que encontraría todas las confirmaciones que tienen 'search_for_this' en algún lugar de un proyecto, utilice la llamada búsqueda "pickaxe", es decir, la opción '-S' para registrar git , que encuentra confirmaciones que introdujeron o eliminaron una cadena dada, o para ser más exactos donde cambió el número de ocurrencias de una cadena determinada.
Jakub Narębski
55
Puede especificar varias ramas o usar la opción '--todos', por ejemplo, 'git log --grep = "cadena en un mensaje de confirmación" --todos "
Jakub Narębski
Esto solo me permitió encontrar un compromiso perdido para 2 días de trabajo. Totalmente salvó mi culo, gracias!
Mike Chamberlain
2
Me he encontrado con algunas situaciones en las que tenía confirmaciones en mi base de datos pero no en mi registro. No sé qué tan común es esto. Estaba probando diferentes puentes hg / git. Creo que también puede surgir con escondites caídos. En cualquier caso, este alias funciona muy bien para detectar esos casos:!git fsck --unreachable | sed -ne 's/^unreachable commit //p' | xargs git log --no-walk
dubiousjim
Tenga en cuenta que eso no incluye la búsqueda de objetos de nota. Eso aún no se ha implementado: git.661346.n2.nabble.com/…
Antony Stubbs
54

En Mercurial, utiliza hg log --keywordpara buscar palabras clave en los mensajes de confirmación y hg log --userpara buscar un usuario en particular. Consulte hg help logotras formas de limitar el registro.

Martin Geisler
fuente
36
Josip escribió que está considerando cambiar a Mercurial y que también le gustaría saber cómo se hace allí.
Martin Geisler
1
hg log -klas búsquedas confirman el nombre de usuario y los nombres de archivo en los conjuntos de cambios también (lo veo en command.py:log), que es una de las pocas cosas que no entiendo en hg. Debería haber opciones separadas para buscar en mensajes de confirmación y nombres de archivo. Parece que hg log --template '{desc}\n'|grepes el camino seguro.
Geoffrey Zheng
@ GeoffreyZheng: hay formas de hacerlo. Consulte "hg help revsets", especialmente las funciones desc (), user () y file (). También hay modificadores de registro hg para la mayoría de este comportamiento. En mi experiencia, aunque -k / keyword () suele ser la forma más útil de buscar cosas.
Kevin Horn
¿Cómo se busca a través del contenido de archivo comprometido real ... las diferencias? Sé que sería una búsqueda lenta, pero quiero hacer una búsqueda profunda de un nombre de función faltante.
Jonathan
Oh, aquí está:hg grep --all <term>
Jonathan
24

Además de la respuesta richq de usar git log -g --grep=<regexp>o git grep -e <regexp> $(git log -g --pretty=format:%h): eche un vistazo a las siguientes publicaciones de blog de Junio ​​C Hamano, actual mantenedor de git


Resumen

Tanto git grep como git log --grep están orientados a líneas , ya que buscan líneas que coincidan con el patrón especificado.

Puede usar git log --grep=<foo> --grep=<bar>(o git log --author=<foo> --grep=<bar>eso se traduce internamente en dos --grep) para buscar confirmaciones que coincidan con cualquiera de los patrones (implícito O semántico).

Debido a que está orientado a la línea, lo útil Y semántico es usar git log --all-match --grep=<foo> --grep=<bar>para encontrar commit que tenga tanto la coincidencia de línea primero como la coincidencia de línea segunda en alguna parte.

Con git greppuede combinar varios patrones (todos los cuales deben utilizar el -e <regexp>formulario) con --or(que es el valor por defecto), --and, --not, (y ). Para grep --all-matchsignifica que el archivo debe tener líneas que coincidan con cada una de las alternativas.

Jakub Narębski
fuente
Hola Jakub, ¿te importaría integrar citas / resúmenes de esas publicaciones de blog aquí? Parece una de las respuestas vintage de solo enlace en este momento.
Nathan Tuggy
11

Sobre la base de la respuesta de rq, encontré que esta línea hace lo que quiero:

git grep "search for something" $(git log -g --pretty=format:%h -S"search for something")

Que informará el ID de confirmación, el nombre de archivo y mostrará la línea correspondiente, de esta manera:

91ba969:testFile:this is a test

... ¿Alguien está de acuerdo en que esta sería una buena opción para ser incluida en el comando estándar git grep?

Sam Hiatt
fuente
5

Cualquier comando que tome referencias como argumentos aceptará la --allopción documentada en la página del manual de la git rev-listsiguiente manera:

   --all
       Pretend as if all the refs in $GIT_DIR/refs/ are listed on the
       command line as <commit>.

Entonces, por ejemplo, git log -Sstring --allse mostrarán todos los commits que mencionan stringy que son accesibles desde una rama o desde una etiqueta (supongo que sus commits colgantes se nombran al menos con una etiqueta).

adl
fuente
3
Este no parece ser el caso git grep, donde --allparece traducirse / usarse como --all-match. Esto me parece un error ... usando Git 1.7.2.3 (usando $(git rev-list --all)trabajos).
azulada
5

Con Mercurial haces un

$ hg grep "search for this" [file...]

Hay otras opciones que reducen el rango de revisiones que se buscan.

Yawar
fuente
1
También me gusta la banderahg grep --all
Jonathan
2

No sé sobre git, pero en Mercurial simplemente canalizaría la salida de hg log a algún script sed / perl / whatever para buscar lo que sea que esté buscando. Puede personalizar la salida del registro hg utilizando una plantilla o un estilo para facilitar la búsqueda, si lo desea.

Esto incluirá todas las ramas con nombre en el repositorio. Mercurial no tiene algo como colgar gotas de afaik.

Kurt Schelfthout
fuente
1
No entiendo cómo esta respuesta es relevante para el problema especificado.
jribeiro
3
Es una respuesta a la pregunta para Mercurial, sobre la cual se pregunta la pregunta original en el último párrafo.
Kurt Schelfthout
1

Para agregar solo una solución más aún no mencionada, tuve que decir que usar el cuadro de búsqueda gráfica de gitg fue la solución más simple para mí. Seleccionará la primera aparición y puede encontrar la siguiente con Ctrl-G.

icarito
fuente
1

Un comando en git que creo que es mucho más fácil encontrar una cadena:

git log --pretty=oneline --grep "string to search"

funciona en Git 2.0.4

Adriano Rosa
fuente