Учитывая хэш блоба, есть ли способ получить список коммитов, у которых этот блоб находится в их дереве?
git
version-control
Readonly
источник
источник
git hash-object
илиsha1("blob " + filesize + "\0" + data)
, а не просто sha1sum содержимого блоба.git log --follow filepath
(и использовать его, чтобы ускорить решение Аристотеля, если хотите).~/.bin
и назовите егоgit-find-object
. Затем вы можете использовать его сgit find-object
.git describe <hash>
: смотрите мой ответ ниже .Ответы:
Оба следующих сценария принимают SHA1 большого двоичного объекта в качестве первого аргумента, а после него, необязательно, любые аргументы, которые
git log
будут понятны. Например,--all
искать во всех ветвях, а не только в текущей, или-g
искать в журнале рефлогов, или что-то еще, что вам нравится.Вот он как скрипт оболочки - короткий и приятный, но медленный:
И оптимизированная версия на Perl, все еще довольно короткая, но намного быстрее:
источник
git rev-parse --verify $theprefix
my $blob_arg = shift; open my $rev_parse, '-|', git => 'rev-parse' => '--verify', $blob_arg or die "Couldn't open pipe to git-rev-parse: $!\n"; my $obj_name = <$rev_parse>; chomp $obj_name; close $rev_parse or die "Couldn't expand passed blob.\n"; $obj_name eq $blob_arg or print "(full blob is $obj_name)\n";
obj_name="$1" shift git log --all --pretty=format:'%T %h %s %n' -- "$@" | while read tree commit cdate subject ; do if [ -z $tree ] ; then continue fi if git ls-tree -r $tree | grep -q "$obj_name" ; then echo "$cdate $commit $@ $subject" fi done
--all
в качестве дополнительного аргумента. (Поиск всех коммитов в репо очень важен в таких случаях, как удаление большого файла из истории репо ).К сожалению, сценарии были немного медленными для меня, поэтому мне пришлось немного оптимизировать. К счастью, у меня был не только хеш, но и путь к файлу.
источник
<hash>
в данный момент<path>
, то удаление<path>
аргумента изgit log
будет работать. Первый возвращаемый результат - это требуемый коммит.С Git 2.16 (Q1 2018),
git describe
было бы хорошим решением, поскольку его учили копать деревья глубже, чтобы найти объект,<commit-ish>:<path>
который ссылается на данный объект BLOB-объекта.Смотрите коммит 644eb60 , коммит 4dbc59a , коммит cdaed0c , коммит c87b653 , коммит ce5b6f9 (16 ноября 2017 г.) и коммит 91904f5 , коммит 2deda00 (02 ноября 2017 г.) от Stefan Beller (
stefanbeller
) .(Слиты Junio C Hamano -
gitster
- в фиксации 556de1a , 28 дек 2017)Это означает, что
git describe
страница man добавляет к целям этой команды:Но:
источник
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | awk '/^blob/ {print substr($0,6)}' | sort --numeric-sort --key=2 -r | head -n 20
, который возвращает вас в топ-20 крупнейших капель. Затем вы можете передать идентификатор BLOB из вышеприведенного выводаgit describe
. Работал как шарм! Спасибо!Я подумал, что это будет вообще полезно, поэтому я написал для этого небольшой скрипт на Perl:
Я положу это на github, когда вернусь домой этим вечером.
Обновление: похоже, кто-то уже сделал это . Тот использует ту же общую идею, но детали отличаются, и реализация намного короче. Я не знаю, что будет быстрее, но производительность здесь, наверное, не проблема!
Обновление 2: моя реализация на несколько порядков быстрее, особенно для большого репозитория. Это
git ls-tree -r
действительно больно.Обновление 3: я должен отметить, что мои комментарии о производительности выше относятся к реализации, о которой я говорил выше в первом обновлении. Реализация Аристотеля сравнима с моей. Подробнее в комментариях для тех, кому интересно.
источник
git rev-parse $commit^{}
Хотя исходный вопрос не требует этого, я думаю, что полезно также проверить область подготовки, чтобы увидеть, есть ли ссылка на BLOB-объект. Я изменил исходный скрипт bash, чтобы сделать это, и нашел то, что ссылалось на поврежденный BLOB-объект в моем хранилище:
источник
Итак ... Мне нужно было найти все файлы с заданным лимитом в репо размером более 8 ГБ с более чем 108 000 ревизий. Я адаптировал Perl-скрипт Аристотеля вместе с Ruby-сценарием, который написал, чтобы достичь полного решения.
Во-первых,
git gc
- сделайте это, чтобы убедиться, что все объекты находятся в пакетных файлах - мы не проверяем объекты не в пакетных файлах.Далее Запустите этот скрипт, чтобы найти все BLOB-объекты в байтах CUTOFF_SIZE. Записать вывод в файл типа «large-blobs.log»
Затем отредактируйте файл, чтобы удалить все ожидаемые объекты и биты INPUT_THREAD вверху. если у вас есть только строки для sha1, которые вы хотите найти, запустите следующий скрипт:
Где
git-find-blob
сценарий ниже.Вывод будет выглядеть так:
И так далее. Каждый коммит, который содержит большой файл в своем дереве, будет указан. если вы
grep
выделите строки, начинающиеся с вкладки, иuniq
у вас будет список всех путей, которые вы можете удалить с помощью filter-branch, или вы можете сделать что-то более сложное.Позвольте мне повторить: этот процесс прошел успешно, на репо 10 ГБ со 108 000 коммитов. Это заняло намного больше времени, чем я ожидал, при работе с большим количеством больших двоичных объектов, хотя через 10 часов мне нужно будет проверить, работает ли бит запоминания ...
источник
-- --all
. (Поиск всех коммитов в репо важен в таких случаях, как тщательное удаление большого файла из истории репо ).Кроме того
git describe
, о чем я упоминал в своем предыдущем ответе ,git log
иgit diff
теперь также получает выгоду от--find-object=<object-id>
опции « », чтобы ограничить результаты изменений, затрагивающих именованный объект.То есть в Git 2.16.x / 2.17 (Q1 2018)
См. Коммит 4d8c51a , коммит 5e50525 , коммит 15af58c , коммит cf63051 , коммит c1ddc46 , коммит 929ed70 (04 января 2018 г.) от Stefan Beller (
stefanbeller
) .(Слиты Junio C Hamano -
gitster
- в фиксации c0d75f0 , 23 января 2018)источник