Jak mogę wyszukać oddziały Git w poszukiwaniu pliku lub katalogu?

323

Jak w Git mogę wyszukać plik lub katalog według ścieżki w wielu oddziałach?

Napisałem coś w oddziale, ale nie pamiętam, który. Teraz muszę to znaleźć.

Wyjaśnienie : Szukam pliku, który utworzyłem w jednym z moich oddziałów. Chciałbym znaleźć ją według ścieżki, a nie według jej zawartości, ponieważ nie pamiętam, co to jest.

Peeja
źródło
Nie jestem pewien co do pytania. Czy ten plik w gałęzi został teraz usunięty? Czy plik został usunięty?
Abizern

Odpowiedzi:

444

git log+ git branchznajdzie to dla ciebie:

% 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

Obsługuje także globbing:

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

Pojedyncze cudzysłowy są konieczne (przynajmniej jeśli używasz powłoki Bash), więc powłoka przekazuje wzorzec glob bez zmian, zamiast go rozszerzać (tak jak w Uniksie find).

Dustin
źródło
2
Działa to, jeśli znasz dokładną ścieżkę do somefile: jeśli potrzebujesz na przykład wyrażenia regularnego nad ścieżką / nazwą pliku, możesz użyć odpowiedzi ididaka.
ShreevatsaR
70
Obsługuje także globbing:git log --all -- **/my_file.png
webmat,
3
Użyłem tego do nieco innego problemu. Próbowałem znaleźć wszystkie pliki * .sql, które podjąłem w konkretnej gałęzi. Więc użyłem git log --grep='branch' --author='me' -- *.sql. Działa jak urok. wersja git 1.7.11.1
thepriebe
1
Uwaga: gitkobsługuje także globbing. To doskonała odpowiedź na @webmat! Jeśli chcesz zobaczyć, gdzie został usunięty / utworzony / itp., Możesz użyć git log --all --stat -- **/my_file.png, w ten sposób nie będziesz musiał zgadywać, czy sprawdzasz go z zatwierdzenia, które go usunęło.
eacousineau
1
@webmat: Pozwoliłem sobie na dodanie do odpowiedzi informacji o globowaniu. Dzięki, że o tym wspomniałeś!
sleske,
65

git ls-tree może pomóc. Aby wyszukać we wszystkich istniejących oddziałach:

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

Zaletą tego jest to, że można również wyszukiwać nazwy plików za pomocą wyrażeń regularnych.

ididak
źródło
3
Kilka, miejmy nadzieję, pomocnych komentarzy: (a) Prawdopodobnie chcesz dodać „-r” do „git ls-tree”, aby znalazł plik, nawet jeśli znajduje się w podkatalogu. (b) Być może fajniejszą alternatywą dla pierwszego wiersza byłoby użycie „git dla każdego odwołania”, np. „dla gałęzi w git for-each-ref --format="%(refname)" refs/heads; do” (c) „git ls-tree - only-name” sprawi, że wyjście będzie bardziej uporządkowane (d) warto w swojej odpowiedzi wskazać, że ma to przewagę nad rozwiązaniem Dustina, a mianowicie, że nie musisz dokładnie znać nazwy pliku - możesz wyszukiwać za pomocą wyrażenia regularnego pasującego do dowolnej części ścieżki
Mark Longair
9
Spakowałem to do skryptu, abyś mógł uruchomić "gitfind.sh <regex>"; sedno to gist.github.com/62d981890eccb48a99dc
Handyman5
3
Pamiętaj, że będzie to wyszukiwać tylko w lokalnych oddziałach. Aby wyszukać oddziały zdalnego śledzenia, użyj refs/remoteszamiast refs/heads. Aby wyszukać wszystko (oddziały lokalne, oddziały i tagi do zdalnego śledzenia), wystarczy użyć refs/.
śleske,
19

Chociaż odpowiedź ididaka jest całkiem fajna, a Handyman5 zapewnia skrypt do jego użycia, uznałem, że stosowanie tego podejścia jest nieco ograniczone.

Czasami musisz szukać czegoś, co może pojawić się / zniknąć z czasem, więc dlaczego nie szukać wbrew wszystkim zatwierdzeniom? Poza tym czasami potrzebujesz pełnej odpowiedzi, a innym razem tylko dopasowania. Oto dwie wersje tych opcji. Umieść te skrypty na swojej ścieżce:

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

Teraz możesz zrobić

$ 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

Zobacz, że używając getopt możesz modyfikować ten skrypt, aby naprzemiennie przeszukiwać wszystkie zatwierdzenia, referencje, referencje / głowy, były pełne, itp.

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

Zapoznaj się z https://github.com/albfan/git-find-file pod kątem możliwej implementacji.

albfan
źródło
Czy chodziło Ci o „Teraz możesz zrobić git-find-file <regex>”? Mam to działa, dziękuję!
Elijah Lynn
1
Osobiście uważam, że o wiele bardziej przydatne jest użycie $ (git branch | cut -c 3-) zamiast $ (git rev-list --all). Nie obchodzi mnie znalezienie szeregu zobowiązań, zależy mi na nazwanych oddziałach.
Campadrenalin
Zmieniłem także skrypty, aby używały $ (git branch | cut -c 3-), ponieważ pętla nad wszystkimi zatwierdzeniami była o wiele za wolna.
i4h
Widząc całe to zamieszanie, które warto jest stworzyć repo. github.com/albfan/git-find-file . Mam kilka problemów, mogę zaproponować więcej lub wysłać PR za to.
albfan
1
@lumbric skrypt instalacyjny na ścieżce działa od razu po wyjęciu z pudełka, jest to funkcja git
albfan
10

Możesz użyć gitk --alli wyszukać zatwierdzone „ścieżki dotykowe” oraz nazwę ścieżki, którą jesteś zainteresowany.

Greg Hewgill
źródło
3
Jak już wspomniano, użyj gitk --all, a następnie w View | Nowy widok, włącz wszystkie gałęzie. Następnie ustaw kryteria wyszukiwania: nazwy plików (z symbolami wieloznacznymi) w przedostatnim polu. Wreszcie: OK.
MikeW
8

Skopiuj i wklej to, aby użyć git find-file SEARCHPATTERN

Drukowanie wszystkich wyszukiwanych gałęzi:

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

Drukuj tylko oddziały z wynikami:

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

Polecenia te doda pewne minimalne skrypty powłoki bezpośrednio do ~/.gitconfigjako globalnego git alias .

lędźwiowy
źródło
szuka tylko w głównej gałęzi
Nasif Imtiaz Ohi
Przeszukuje wszystkie lokalne oddziały
Leonardo Herrera