¿Es posible realizar una 'búsqueda grep' en todas las ramas de un proyecto Git?

Respuestas:

189

La pregunta " ¿Cómo grep (buscar) el código comprometido en el historial de git? " Recomienda:

 git grep <regexp> $(git rev-list --all)

Eso busca a través de todos los commits, que deben incluir todas las ramas.

Otra forma sería:

git rev-list --all | (
    while read revision; do
        git grep -F 'yourWord' $revision
    done
)

Puedes encontrar aún más ejemplos en este artículo :

Intenté lo anterior en un proyecto lo suficientemente grande como para que git se quejara del tamaño del argumento, por lo que si se encuentra con este problema, haga algo como:

git rev-list --all | (while read rev; do git grep -e <regexp> $rev; done)

(vea una alternativa en la última sección de esta respuesta, a continuación)

No olvides esas configuraciones, si las quieres:

# Allow Extended Regular Expressions
git config --global grep.extendRegexp true
# Always Include Line Numbers
git config --global grep.lineNumber true

Este alias también puede ayudar:

git config --global alias.g "grep --break --heading --line-number"

Nota: chernjie sugirió que git rev-list --alles una exageración.

Un comando más refinado puede ser:

git branch -a | tr -d \* | xargs git grep <regexp>

Lo que le permitirá buscar solo sucursales (incluidas las sucursales remotas)

Incluso puede crear un alias bash / zsh para ello:

alias grep_all="git branch -a | tr -d \* | xargs git grep"
grep_all <regexp>

Actualización de agosto de 2016: RM recomienda en los comentarios

Obtuve un " fatal: bad flag '->' used after filename" al probar la git branchversión. El error se asoció con una HEADnotación de alias.

Lo resolví agregando un sed '/->/d'en la tubería, entre el try los xargscomandos.

 git branch -a | tr -d \* | sed '/->/d' | xargs git grep <regexp>

Es decir:

alias grep_all="git branch -a | tr -d \* | sed '/->/d' | xargs git grep"
grep_all <regexp>
VonC
fuente
No es una buena idea canalizar la salida de git branchtr o sed; git branches un comando de porcelana destinado al consumo humano. Consulte stackoverflow.com/a/3847586/2562319 para conocer las alternativas preferidas.
jbyler
@jbyler Buen punto. Irónicamente, publiqué la respuesta en porcelana mucho antes de esta respuesta: stackoverflow.com/a/6978402/6309 . Y lo uso, por ejemplo, en stackoverflow.com/a/19206916/6309 .
VonC
Sí, bien. Mirando las otras respuestas, creo que la respuesta de @errordeveloper es la más limpia: stackoverflow.com/a/21284342/2562319 : "git grep <regexp> $ (git for-each-ref --format = '% (refname) 'refs /) "
jbyler
1
¿Hay alguna forma de mostrar el nombre de la rama que coincide con la búsqueda?
franksands
63

git log puede ser una forma más efectiva de buscar texto en todas las ramas, especialmente si hay muchas coincidencias y desea ver primero los cambios más recientes (relevantes).

git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

Estos comandos de registro enumeran confirmaciones que agregan o eliminan la cadena de búsqueda / expresión regular dada, (generalmente) más reciente primero. La -popción hace que la diferencia relevante se muestre donde se agregó o eliminó el patrón, por lo que puede verlo en contexto.

Después de encontrar una confirmación relevante que agregue el texto que estaba buscando (por ejemplo, 8beeff00d), busque las ramas que contienen la confirmación:

git branch -a --contains 8beeff00d
Edward Anderson
fuente
22

Encontré esto más útil:

git grep -i foo `git for-each-ref --format='%(refname)' refs/`

Tendría que ajustar los últimos argumentos dependiendo de si desea ver solo las ramas remotas frente a las locales, es decir:

  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/remotes)
  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/heads)

El alias que creé se ve así:

grep-refs = !sh -c 'git grep "$0" "$@" "$(git for-each-ref --format=\"%(refname)\"" refs/)'
desarrollador de errores
fuente
1
Alias ​​interesante +1. Más preciso que en mi respuesta.
VonC
¿Cómo hacer que su alias funcione para la búsqueda de frases? Cuando paso "foo bar" como parámetro, obtengo: fatal: argumento ambiguo 'bar': revisión desconocida o ruta no en el árbol de trabajo. Use '-' para separar las rutas de las revisiones
jutky
Intenta escapar del espacio: "foo \ bar"
Garry Gomez
Esta será claramente la respuesta aceptada;) Lo he expandido para buscar solo en las últimas ramas de mi proyecto (Tengo más de 500, no preguntes, y cada grep toma alrededor de 4 segundos, así que no quiero ni necesito para buscar en más de, digamos, 100 más recientes). Para esto he actualizado el git for-each-refcon --sort=-committerdate --count=100! Gracias por la idea original!
Vser
6

Es posible hacerlo de dos maneras comunes: alias Bash o Git

Aquí hay tres comandos:

  1. git grep-branch - Buscar en todas las sucursales locales y remotas
  2. git grep-branch-local - Buscar solo en sucursales locales
  3. git grep-branch-remote - Solo ramas remotas

El uso es el mismo que git grep

git grep-branch "find my text"
git grep-branch --some-grep-options "find my text"

GREP usando: alias Git

Archivo ~ / .gitconfig

Los comandos deben agregarse manualmente al ~/.gitconfigarchivo, porque git config --global aliasevalúa el código complejo que agregas y lo desordena.


[alias]
    grep-branch        = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | xargs git grep $@; };f "
    grep-branch-remote = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | grep '^remotes' | xargs git grep $@; };f"
    grep-branch-local  = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' -e '^remotes' | xargs git grep $@;  };f "

Nota: Cuando agrega alias y no se ejecutan, compruebe las barras diagonales inversas \que pueden requerir un escape adicional \\en comparación con los comandos bash .

  • git branch -a - Mostrar todas las ramas;
  • sed -e 's/[ \\*]*//'- Recortar espacios (desde branch -a) y * (el nombre de la rama activa lo tiene);
  • grep -v -e '\\->'- Ignorar nombres complejos como remotes/origin/HEAD -> origin/master;
  • grep '^remotes' - Obtenga todas las ramas remotas;
  • grep -v -e '^remotes'- Obtener ramas excepto ramas remotas;

Ejemplo git grep-branch-local -n getTastyCookies

-n Prefije el número de línea a líneas coincidentes.

[user@pc project]$ git grep-branch-local -n getTastyCookies

dev:53:modules/factory/getters.php:function getTastyCookies($user);
master:50:modules/factory/getters.php:function getTastyCookies($user)

La estructura actual es:

: - separador

  1. Rama: dev
  2. Número de línea: 53
  3. Ruta de archivo: modules/factory/getters.php
  4. Línea a juego: function getTastyCookies($user)

GREP usando: BASH

Como debe saber: los comandos Bash deben almacenarse en .shscripts o ejecutarse en un shell.

Solo sucursales locales

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' -e '^remotes' | xargs git grep "TEXT"

Solo ramas remotas

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | grep '^remotes' | xargs git grep "TEXT"

Sucursales locales y remotas

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | xargs git grep "TEXT"
Devaldo
fuente
Suena bien, pero recibí este error de git grep-branch "find my text":fatal: ambiguous argument 'client': both revision and filename
nealmcb
¿Por qué usar siempre -a, que muestra todas las ramas? Sugeriría usar opciones para el git branchcomando para separar los braches. Al mirar las ramas locales, solo hay una sola *, por lo que no es necesario escapar por sed. Entonces: solo git branch | sed -e 's/*/ /' | xargs git grep "TEXT"para sucursales locales, solo git branch -r | grep -v -- "->" | xargs git grep "TEXT"para sucursales remotas y git branch -a | grep -v -- "->" | xargs git grep "TEXT"para todas las sucursales
jalanb
4

Así es como lo hago:

git for-each-ref --format='%(*refname)' | xargs git grep SEARCHTERM
William Entriken
fuente
2
La única solución que funcionó para mí en Windows (en Git bash)
Ivan
4

Si le da a commit un valor hash SHA-1, git grephaga que busque en ellos, en lugar de la copia de trabajo.

Para buscar todas las ramas, puede obtener todos los árboles con git rev-list --all. Ponlo todo con

git grep "regexp" $(git rev-list --all)

... y ten paciencia

CharlesB
fuente