Можно ли использовать Git для поиска совпадающих имен файлов в репозитории?

Просто скажу, что у меня есть файл: "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, но я надеялся избежать сканирования всех подкаталогов, ищущих экземпляры имени файла.

Ответ 1

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

git ls-files '*/HelloWorld.pm'

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

git grep some-string -- '*/HelloWorld.pm'

Ответ 2

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

Поскольку я не мог найти ответ, который действительно ищет всю историю фиксации, я написал быструю грубую силу script 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.

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

Ответ 3

Try:

git ls-tree -r HEAD | grep HelloWorld.pm

Ответ 4

git ls-files | grep -i HelloWorld.pm

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

Ответ 5

[Немного о злоупотреблении комментариями, я признаю, но я не могу комментировать и думал, что улучшу ответ @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 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), когда вывод команды, который вы перебираете, разделяется newlines (или read -d'', когда вывод разделяется пустой строкой $'\0'). В то время как git rev-list --all гарантированно использует 40-байтные шестнадцатеричные строки (без пробелов), я никогда не хочу рисковать. Теперь я могу легко изменить команду из git rev-list --all на любую команду, которая создает строки

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

Ответ 6

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

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