¿Cómo puedo buscar ramas de Git para un archivo o directorio?

323

En Git, ¿cómo podría buscar un archivo o directorio por ruta en varias ramas?

He escrito algo en una rama, pero no recuerdo cuál. Ahora necesito encontrarlo.

Aclaración : estoy buscando un archivo que creé en una de mis ramas. Me gustaría encontrarlo por ruta, y no por su contenido, ya que no recuerdo cuáles son los contenidos.

Peeja
fuente
No estoy claro sobre la pregunta. ¿Estaba este archivo en una rama que ahora se ha eliminado? ¿Se eliminó el archivo?
Abizern

Respuestas:

444

git log+ git branchlo encontrará por usted:

% git log --all -- somefile

commit 55d2069a092e07c56a6b4d321509ba7620664c63
Author: Dustin Sallings <[email protected]>
Date:   Tue Dec 16 14:16:22 2008 -0800

    added somefile


% git branch -a --contains 55d2069
  otherbranch

También es compatible con el engorde:

% git log --all -- '**/my_file.png'

Las comillas simples son necesarias (al menos si se usa el shell Bash) para que el shell pase el patrón glob a git sin cambios, en lugar de expandirlo (al igual que con Unix find).

Dustin
fuente
2
Esto funciona si conoce la ruta exacta a somefile: si necesita buscar expresiones regulares sobre la ruta / nombre de archivo, por ejemplo, puede usar la respuesta de ididak.
ShreevatsaR
70
También es compatible con el engorde:git log --all -- **/my_file.png
webmat
3
Usé esto para un problema ligeramente diferente. Estaba tratando de encontrar todos los archivos * .sql que había comprometido con una rama en particular. Entonces yo solía git log --grep='branch' --author='me' -- *.sql. Trabajado como un encanto. git versión 1.7.11.1
thepriebe
1
Tenga en cuenta que también es gitkcompatible con el globbing. Esa es una excelente respuesta @webmat! Si desea ver dónde se ha eliminado / creado / etc., puede usarlo git log --all --stat -- **/my_file.png, de esa manera no tendrá que adivinar si lo está extrayendo de una confirmación que lo eliminó.
eacousineau
1
@webmat: Me tomé la libertad de agregar su información sobre globbing a la respuesta. Gracias por mencionarlo!
sleske
65

git ls-tree podría ayudar. Para buscar en todas las sucursales existentes:

for branch in `git for-each-ref --format="%(refname)" refs/heads`; do
  echo $branch :; git ls-tree -r --name-only $branch | grep '<foo>'
done

La ventaja de esto es que también puede buscar con expresiones regulares el nombre del archivo.

ididak
fuente
3
Algunos comentarios con suerte útiles: (a) Probablemente desee agregar "-r" a "git ls-tree" para que encuentre el archivo incluso si está en un subdirectorio. (b) Una alternativa quizás más ordenada a la primera línea sería usar "git for-each ref", por ejemplo, "for branch in git for-each-ref --format="%(refname)" refs/heads; do" (c) "git ls-tree --name-only" hará que la salida sea más ordenada (d) podría valer la pena señalar en su respuesta que hay una ventaja de esto sobre la solución de Dustin, es decir, que no necesita saber exactamente el nombre de archivo; puede buscar por expresión regular que coincida con cualquier parte de la ruta
Mark Longair
99
Envolví esto en un script para que pueda ejecutar "gitfind.sh <regex>"; la esencia es gist.github.com/62d981890eccb48a99dc
Handyman5
3
Tenga en cuenta que esto solo buscará en las sucursales locales . Para buscar ramas de seguimiento remoto, use en refs/remoteslugar de refs/heads. Para buscar todo (sucursales locales, sucursales de seguimiento remoto y etiquetas), simplemente use refs/.
sleske
19

Aunque la respuesta de ididak es bastante buena, y Handyman5 proporciona un script para usarlo, me pareció un poco restringido usar ese enfoque.

A veces necesitas buscar algo que pueda aparecer / desaparecer con el tiempo, así que ¿por qué no buscar en todas las confirmaciones? Además de eso, a veces necesitas una respuesta detallada, y otras veces solo confirmas coincidencias. Aquí hay dos versiones de esas opciones. Pon estos scripts en tu camino:

git-find-file

for branch in $(git rev-list --all)
do
  if (git ls-tree -r --name-only $branch | grep --quiet "$1")
  then
     echo $branch
  fi
done

git-find-file-verbose

for branch in $(git rev-list --all)
do
  git ls-tree -r --name-only $branch | grep "$1" | sed 's/^/'$branch': /'
done

Ahora puedes hacer

$ git find-file <regex>
sha1
sha2

$ git find-file-verbose <regex>
sha1: path/to/<regex>/searched
sha1: path/to/another/<regex>/in/same/sha
sha2: path/to/other/<regex>/in/other/sha

Vea que usando getopt puede modificar ese script para alternar la búsqueda en todos los commits, refs, refs / heads, estado detallado, etc.

$ git find-file <regex>
$ git find-file --verbose <regex>
$ git find-file --verbose --decorated --color <regex>

Consulte https://github.com/albfan/git-find-file para una posible implementación.

albfan
fuente
¿Querías decir "Ahora puedes hacer git-find-file <regex>"? Lo tengo funcionando, gracias!
Elijah Lynn el
1
Personalmente, encuentro mucho más útil usar $ (git branch | cut -c 3-) en lugar de $ (git rev-list --all). No me importa encontrar un montón de commits, me importan las ramas con nombre.
Campadrenalin
También cambié los scripts para usar $ (git branch | cut -c 3-) ya que el ciclo sobre todos los commits era demasiado lento.
i4h
Visto todo el escándalo, creo que vale la pena crear un repositorio para esto. github.com/albfan/git-find-file . He abierto algunos problemas, siéntase libre de proponer más o enviar relaciones públicas para ello.
albfan
1
El script de instalación de @lumbric en la ruta funciona de fábrica, es una característica de git
albfan
10

Puede usar gitk --ally buscar confirmaciones "rutas de contacto" y el nombre de ruta que le interesa.

Greg Hewgill
fuente
3
Como se indicó, use gitk --all, luego en Ver | Nueva vista, habilite Todas las ramas. Luego establezca sus criterios de búsqueda: nombres de archivo (con comodines) en el penúltimo campo. Finalmente: ok.
MikeW
8

Copia y pega esto para usar git find-file SEARCHPATTERN

Impresión de todas las ramas buscadas:

git config --global alias.find-file '!for branch in `git for-each-ref --format="%(refname)" refs/heads`; do echo "${branch}:"; git ls-tree -r --name-only $branch | nl -bn -w3 | grep "$1"; done; :'

Imprima solo ramas con resultados:

git config --global alias.find-file '!for branch in $(git for-each-ref --format="%(refname)" refs/heads); do if git ls-tree -r --name-only $branch | grep "$1" > /dev/null; then  echo "${branch}:"; git ls-tree -r --name-only $branch | nl -bn -w3 | grep "$1"; fi; done; :'

Estos comandos añadir algunos scripts de shell mínimas directamente a su ~/.gitconfigtan alias git mundial .

lumbric
fuente
solo está buscando en la rama maestra
Nasif Imtiaz Ohi
Busca en todas las sucursales locales
Leonardo Herrera