Могу ли я использовать Git для поиска подходящих имен файлов в хранилище? - PullRequest
67 голосов
/ 10 ноября 2008

Просто скажите, что у меня есть файл "HelloWorld.pm" в нескольких подкаталогах в репозитории Git.

Я хотел бы выполнить команду, чтобы найти полные пути ко всем файлам, соответствующим "HelloWorld.pm":

Например:

/path/to/repository/HelloWorld.pm
/path/to/repository/but/much/deeper/down/HelloWorld.pm
/path/to/repository/please/dont/make/me/search/through/the/lot/HelloWorld.pm

Как я могу использовать Git, чтобы эффективно найти все полные пути, которые соответствуют заданному имени файла?

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

Ответы [ 6 ]

99 голосов
/ 15 апреля 2011

git ls-files предоставит вам список всех файлов в хранилище. Вы можете передать шаблон, чтобы получить файлы, соответствующие этому шаблону.

git ls-files '*/HelloWorld.pm'

Если вы хотите найти набор файлов и просмотреть их содержимое, вы можете сделать это с git grep:

git grep some-string -- '*/HelloWorld.pm'
43 голосов
/ 05 августа 2011

Хм, оригинальный вопрос был о хранилище. Репозиторий содержит более 1 коммита (по крайней мере, в общем случае), но ответы, данные перед поиском, выполняются только через один коммит.

Поскольку я не смог найти ответ, который действительно просматривал бы всю историю коммитов, я написал скрипт быстрого перебора git-find-by-name, который принимает (почти) все коммиты.

#! /bin/sh
tmpdir=$(mktemp -td git-find.XXXX)
trap "rm -r $tmpdir" EXIT INT TERM

allrevs=$(git rev-list --all)
# well, nearly all revs, we could still check the log if we have
# dangling commits and we could include the index to be perfect...

for rev in $allrevs
do
  git ls-tree --full-tree -r $rev >$tmpdir/$rev 
done

cd $tmpdir
grep $1 * 

Может быть, есть более элегантный способ.

Обратите внимание на тривиальный способ передачи параметра в grep, чтобы он соответствовал частям имени файла. Если это нежелательно, закрепите свое поисковое выражение и / или добавьте подходящие параметры grep.

Для глубокой истории вывод может быть слишком шумным, я подумал о скрипте, который преобразует список ревизий в диапазоне, как противоположность тому, что может сделать git rev-list. Но до сих пор это осталось мыслью.

21 голосов
/ 10 ноября 2008

Попробуйте:

git ls-tree -r HEAD | grep HelloWorld.pm
7 голосов
/ 18 июня 2014
git ls-files | grep -i HelloWorld.pm

grep -i делает регистр нечувствительным к регистру.

3 голосов
/ 11 мая 2013

[Это немного злоупотребление комментариями, я признаю, но я пока не могу комментировать и думал, что улучшу ответ @ uwe-geuder.]

#!/bin/bash
#
#

# I'm using a fixed string here, not a regular expression, but you can easily
# use a regular expression by altering the call to grep below.
name="$1"

# Verify usage.
if [[ -z "$name" ]]
then
    echo "Usage: $(basename "$0") <file name>" 1>&2
    exit 100
fi  

# Search all revisions; get unique results.
while IFS= read rev
do
    # Find $name in $rev's tree and only use its path.
    grep -F -- "$name" \
        <(git ls-tree --full-tree -r "$rev" | awk '{ print $4 }')
done < \
    <(git rev-list --all) \
    | sort -u

Снова +1 к @ uwe-geuder за отличный ответ.

Если вас интересует сам BASH:

Если вам не гарантировано разделение слов в цикле for (как, например, при использовании массива, подобного следующему: for item in "${array[@]}"), я настоятельно рекомендую использовать while IFS= read var ; do ... ; done < <(command), когда вывод команды, по которой выполняется цикл, разделяется переводы строки (или read -d'', когда выходные данные разделены пустой строкой $'\0'). Хотя git rev-list --all гарантированно использует 40-байтовые шестнадцатеричные строки (без пробелов), я никогда не хотел рисковать. Теперь я могу легко изменить команду с git rev-list --all на любую команду, которая производит строки

Я также рекомендую использовать встроенные механизмы BASH для ввода ввода и фильтрации вывода вместо временных файлов.

1 голос
/ 05 декабря 2015

Сценарий от Uwe Geuder (@ uwe-geuder) великолепен, но на самом деле нет необходимости записывать каждый вывод ls-tree в его собственный каталог, без фильтрации.

Намного быстрее и с меньшим объемом памяти: запустите grep на выходе и сохраните его, как показано в этом gist

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...