Получить вывод git revlist в машиночитаемом формате
Я использую git rev-list --all --format="%H%n%B"
получить все (доступные) коммиты из git-репозитория.
Мне нужно иметь возможность анализировать полученный результат в отдельных полях для хэширования коммитов, а также необработанного тела.
-> Есть ли надежный способ отформатировать вывод таким образом, чтобы его можно было проанализировать?
Несмотря на то, что хеш коммита имеет фиксированную длину, необработанное тело содержит неизвестное количество строк, что вводит необходимость в каком-либо разделителе. Я думал об упаковке вывода в xml-подобных тегах, например --format="<record>%H%n%B</record>"
, но это имеет очевидный недостаток, что строка </record>
, если вставлено в необработанное тело, будет тормозить синтаксический анализатор. Конечно, я мог бы сделать разделители более сложными, чтобы уменьшить риск того, что кто-то вставит их в сообщения коммита, но мне действительно нужен персонаж, который технически не может быть частью исходного тела. Я попытался использовать управляющий символ ASCII для разделителя записей "\x1F". Тем не менее, он не вставляется в вывод, как предполагалось, а печатается как есть.
Основываясь на ответе от Торека (спасибо!), Я смог создать небольшую функцию Python:
from subprocess import Popen, PIPE
from codecs import decode
directory = '/path/to/git/repo'
git_rev_list = Popen(['git', '-C', directory, 'rev-list', '--all'], stdout=PIPE)
git_cat_file = Popen(['git', '-C', directory, 'cat-file', '--batch'],
stdin=git_rev_list.stdout, stdout=PIPE)
while True:
line = git_cat_file.stdout.readline()
try:
hash_, type_, bytes_ = map(decode, line.split())
except ValueError:
break
content = decode(git_cat_file.stdout.read(int(bytes_)))
if type_ == 'commit':
yield _get_commit(hash_, content)
git_cat_file.stdout.readline()
2 ответа
Чтобы вставить ASCII RS через формат, используйте %x1F
не \x1F
,
В общем, вам лучше всего выполнять поиск тела отдельно, так как %B
может буквально расширяться на что угодно, и нет никакой защиты, доступной. Обычно достаточно легко запустить git log --no-walk --pretty=format:%B
на каждом коммите по одному, это просто медленно.
Для ускорения вы можете использовать git cat-file --batch
или аналогичный, который обеспечивает простой способ анализа данных в программе: каждому объекту предшествует его размер. Коммитить объекты довольно легко разбирать, так как %B
Эквивалент - это просто "все после первых двух соседних символов новой строки". Таким образом, вместо:
git rev-list --all --format=something-tricky | ...
ты можешь использовать:
git rev-list --all | git cat-file --batch | ...
и измените ожидаемый формат ввода, чтобы ожидать последовательность <hash> <type> <size-in-bytes> LF <bytes>
, Или добавьте директивы формата к git cat-file
угробить тип объекта (но я бы сохранил его, поскольку это означает, что вы можете отличать коммиты от аннотированных тегов).
Вы были на правильном пути с "\x1F", но это должен быть "%x1F", и вы готовы идти.
Из man-страницы git rev-list:
· %x00: print a byte from a hex code