Как я могу искать в ветках Git файл или каталог?

323

В Git, как я могу искать файл или каталог по пути по нескольким веткам?

Я написал что-то в ветке, но не помню какой. Теперь мне нужно найти это.

Уточнение : я ищу файл, который я создал в одной из моих веток. Я хотел бы найти его по пути, а не по его содержимому, поскольку я не помню, что это за содержимое.

Peeja
источник
Я неясен по этому вопросу. Был ли этот файл в ветке, которая сейчас удалена? Был ли файл удален?
Abizern

Ответы:

444

git log+ git branchнайдет это для вас:

% 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

Поддерживает Globbing тоже:

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

Одиночные кавычки необходимы (по крайней мере, если используется оболочка Bash), поэтому оболочка передает шаблон glob неизменному git, а не расширяет его (как в Unix find).

Dustin
источник
2
Это работает, если вы знаете точный путь к somefile: если вам нужен регулярный поиск по пути / имени файла, например, тогда вы можете использовать ответ ididak.
ShreevatsaR
70
Поддерживает также git log --all -- **/my_file.png
globbing
3
Я использовал это для немного другой проблемы. Я пытался найти все файлы * .sql, которые я зафиксировал в определенной ветке. Так я и использовал git log --grep='branch' --author='me' -- *.sql. Работал как шарм. git version 1.7.11.1
thepriebe
1
Обратите внимание, что gitkподдерживает также globbing. Это отличный ответ @webmat! Если вы хотите увидеть, где он был удален / создан / и т.д., вы можете использовать его git log --all --stat -- **/my_file.pngтаким образом, что вам не нужно будет угадывать, извлекаете ли вы его из коммита, который его удалил.
Eacousineau
1
@webmat: я позволил себе добавить в ответ твою информацию о глобализации. Спасибо за упоминание этого!
Слеське
65

мерзавец-дерево может помочь. Для поиска по всем существующим веткам:

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

Преимущество этого состоит в том, что вы также можете искать с помощью регулярных выражений имя файла.

ididak
источник
3
Несколько, надеюсь, полезных комментариев: (a) Возможно, вы захотите добавить «-r» в «git ls-tree», чтобы он нашел файл, даже если он находится в подкаталоге. (b) Возможно, более подходящей альтернативой первой строке было бы использование «git for-each ref», например «for branch in git for-each-ref --format="%(refname)" refs/heads; do» (c) «git ls-tree --name-only» сделает выходной Tidier (d) может быть стоит указать в своем ответе, что это преимущество перед решением Дастина, а именно то, что вам не нужно точно знать имя файла - вы можете искать по регулярному выражению, совпадающему с любой частью пути
Марк Лонгэйр
9
Я обернул это в скрипт, чтобы вы могли запустить "gitfind.sh <regex>"; суть gist.github.com/62d981890eccb48a99dc
Handyman5
3
Обратите внимание, что это будет искать только через местные филиалы. Для поиска веток удаленного отслеживания используйте refs/remotesвместо refs/heads. Чтобы искать все (локальные филиалы, удаленное отслеживание веток и теги), просто используйте refs/.
Слеське
19

Хотя отклик ididak довольно крутой, и Handyman5 предоставляет скрипт для его использования, я нашел его немного ограниченным в использовании этого подхода.

Иногда вам нужно искать что-то, что может появиться / исчезнуть со временем, так почему бы не выполнить поиск по всем коммитам? Кроме того, иногда вам нужен подробный ответ, а в других случаях фиксируются только совпадения. Вот две версии этих опций. Поместите эти сценарии на свой путь:

ГИТ-находка-файл

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

ГИТ-находка-файлы многословных

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

Теперь вы можете сделать

$ 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

Обратите внимание, что с помощью getopt вы можете изменить этот скрипт, чтобы чередовать поиск по всем коммитам, ссылкам, ссылкам / заголовкам, многословности и т. Д.

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

Проверьте https://github.com/albfan/git-find-file для возможной реализации.

albfan
источник
Вы имели в виду "Теперь вы можете сделать git-find-file <regex>"? Я получил это работает, спасибо!
Элайджа Линн
1
Лично я считаю гораздо более полезным использовать $ (git branch | cut -c 3-) вместо $ (git rev-list --all). Меня не волнует поиск группы коммитов, меня интересуют именованные ветви.
Кампадреналин
Я также изменил сценарии на использование $ (git branch | cut -c 3-), поскольку цикл по всем коммитам был слишком медленным.
4
Видел всю суету, которую стоит, чтобы создать репо для этого. github.com/albfan/git-find-file . У меня открыты некоторые вопросы, не стесняйтесь предлагать больше или присылать PR для этого.
Альбфан
1
@lumbric установка скрипта на пути работает из коробки, это функция git
albfan
10

Вы можете использовать gitk --allи искать коммиты "трогательные пути" и интересующий вас путь.

Грег Хьюгилл
источник
3
Как уже говорилось, используйте gitk --all, затем в View | Новый вид, включите все ветви. Затем установите критерии поиска: имена файлов (с подстановочными знаками) в предпоследнем поле. Наконец: ОК.
MikeW
8

Скопируйте и вставьте это, чтобы использовать git find-file SEARCHPATTERN

Печать всех найденных веток:

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

Печатайте только ветки с результатами:

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

Эти команды добавят некоторые минимальные скрипты прямо в ~/.gitconfigкачестве глобального мерзавца псевдонима .

lumbric
источник
это только поиск в основной ветке
Насиф Имтиаз Охи
Это поиск во всех местных филиалах
Леонардо Эррера