Come posso cercare nei rami Git un file o una directory?


323

In Git, come posso cercare un file o una directory per percorso attraverso un numero di rami?

Ho scritto qualcosa in un ramo, ma non ricordo quale. Ora devo trovarlo.

Chiarimento : sto cercando un file che ho creato su uno dei miei rami. Mi piacerebbe trovarlo per percorso e non per contenuto, poiché non ricordo quali siano i contenuti.


Non sono chiaro sulla domanda. Questo file si trovava in un ramo che è stato eliminato? Il file è stato cancellato?
Abizern,

Risposte:


444

git log+ git branchlo troverà per te:

% git log --all -- somefile

commit 55d2069a092e07c56a6b4d321509ba7620664c63
Author: Dustin Sallings <dustin@spy.net>
Date:   Tue Dec 16 14:16:22 2008 -0800

    added somefile


% git branch -a --contains 55d2069
  otherbranch

Supporta anche il globbing:

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

Le virgolette singole sono necessarie (almeno se si utilizza la shell Bash) in modo che la shell passi il pattern glob per rimanere invariato, invece di espanderlo (proprio come con Unix find).


2
Funziona se conosci il percorso esatto per somefile: se hai bisogno di una ricerca regex sul percorso / nome file, ad esempio, puoi usare la risposta di ididak.
ShreevatsaR,

70
Supporta anche il git log --all -- **/my_file.png
globbing

3
L'ho usato per un problema leggermente diverso. Stavo cercando di trovare tutti i file * .sql che avevo assegnato a un determinato ramo. Quindi ho usato git log --grep='branch' --author='me' -- *.sql. Ha funzionato come un fascino. versione git 1.7.11.1
thepriebe,

1
Nota che gitksupporta anche il globbing. Questa è un'ottima risposta @webmat! Se vuoi vedere dove è stato eliminato / creato / etc, puoi usarlo git log --all --stat -- **/my_file.png, in questo modo non dovrai indovinare se lo stai verificando da un commit che lo ha eliminato.
eacousineau,

1
@webmat: mi sono preso la libertà di aggiungere le tue informazioni sul globbing alla risposta. Grazie per averlo menzionato!
sleske,

65

git ls-tree potrebbe aiutare. Per cercare in tutte le filiali esistenti:

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

Il vantaggio è che puoi anche cercare con espressioni regolari il nome del file.


3
Alcuni commenti sperabilmente utili: (a) Probabilmente vorrai aggiungere "-r" a "git ls-tree" in modo che possa trovare il file anche se si trova in una sottodirectory. (b) Un'alternativa forse più ordinata alla prima riga sarebbe quella di usare "git for-each ref", ad esempio "per branch in git for-each-ref --format="%(refname)" refs/heads; do" (c) "git ls-tree --name-only" renderà più ordinato l'output (d) potrebbe valere la pena sottolineare nella risposta che esiste un vantaggio rispetto alla soluzione di Dustin, vale a dire che non è necessario conoscere esattamente il nome del file: è possibile eseguire la ricerca per espressione regolare corrispondente a qualsiasi parte del percorso
Mark Longair

9
L'ho inserito in uno script in modo da poter eseguire "gitfind.sh <regex>"; the gist is gist.github.com/62d981890eccb48a99dc
Handyman5

3
Si noti che questo cercherà solo tra le filiali locali . Per cercare filiali di tracciamento remoto, utilizzare refs/remotesinvece di refs/heads. Per cercare tutto (filiali locali, filiali e tag di tracciamento remoto), basta usare refs/.
sleske

19

Sebbene la risposta di ididak sia piuttosto interessante, e Handyman5 fornisce uno script per usarlo, ho trovato un po 'limitato l'uso di questo approccio.

A volte è necessario cercare qualcosa che possa apparire / scomparire nel tempo, quindi perché non cercare contro tutti i commit? Oltre a ciò, a volte hai bisogno di una risposta dettagliata e altre volte commettono solo corrispondenze. Ecco due versioni di queste opzioni. Inserisci questi script sul tuo percorso:

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

Adesso puoi farlo

$ 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

Vedi che usando getopt puoi modificare quello script per alternare la ricerca di tutti i commit, ref, ref / head, stato dettagliato, ecc.

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

Controlla https://github.com/albfan/git-find-file per una possibile implementazione.


Intendevi "Ora puoi fare git-find-file <regex>"? Ho funzionato, grazie!
Elijah Lynn

1
Personalmente trovo molto più utile usare $ (git branch | cut -c 3-) invece di $ (git rev-list --all). Non mi interessa trovare un sacco di impegni, mi preoccupo per i rami con nome.
Campadrenalin,

Ho anche cambiato gli script per usare $ (git branch | cut -c 3-) poiché il loop su tutti i commit era troppo lento.
i4h,

Visto tutto il clamore che valgo per creare un repository per questo. github.com/albfan/git-find-file . Ho aperto alcuni problemi, sentiti libero di proporne di più o di inviare PR per questo.
albfan,

1
@lumbric install script on path funziona fuori dagli schemi, è una funzionalità git
albfan

10

È possibile utilizzare gitk --alle cercare commit "percorsi toccanti" e il nome percorso a cui si è interessati.


3
Come detto, usa gitk --all, quindi in Visualizza | Nuova vista, abilita tutti i rami. Quindi imposta i criteri di ricerca: nomi file (con caratteri jolly) nel penultimo campo. Finalmente: OK.
MikeW,

8

Copia e incolla questo per usare git find-file SEARCHPATTERN

Stampa di tutti i rami cercati:

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; :'

Stampa solo rami con risultati:

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; :'

Questi comandi aggiungere alcuni script di shell minime direttamente sul tuo ~/.gitconfigcome alias git globale .


sta solo cercando nel ramo principale
Nasif Imtiaz Ohi,

Cerca in tutte le filiali locali
Leonardo Herrera il

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.