Является ли git log --pretty=‹красивый формат› фарфоровой или сантехнической командой?

Я создаю несколько сценариев и программ, которые извлекают информацию о коммите, используя

git log --pretty=<my format> -1 <commit>

Интересно, подходит ли вывод этой команды для анализа программами (сантехника) или предназначен только для представления людям (фарфор). Например, в некоторых проектах я получаю коммит SHA + имя автора + сводку коммита следующим образом:

git log --pretty="%H%n%an%n%s" -1 HEAD

Затем я разбиваю выходную строку на символ новой строки (у меня Linux).

Кроме того, в некоторых случаях я также делаю что-то вроде этого:

git log --pretty='[%h] %an: %s' -1 HEAD

А затем проанализируйте результат с помощью следующего регулярного выражения, ожидая, что короткий SHA, имя автора и сводка коммита находятся в захваченных группах:

^\[(\w+)\] ([^:]+): (.*)$

Это хороший подход? Если нет, то какой предпочтительный способ программного получения информации о коммитах?


person iBug    schedule 02.12.2018    source источник
comment
пожалуйста, как, черт возьми, этот вопрос неясен?   -  person iBug    schedule 02.12.2018
comment
Я предпочитаю, чтобы это фарфоровая команда из-за этой (не по теме) подсказки: в Pro Git v2 Глава 10.1 говорит, что первые девять глав этой книги посвящены почти исключительно командам фарфора, а git log с машинно-ориентированным форматом упоминается в главе 2.3, которая входит в первые девять глав этой книги.   -  person Geno Chen    schedule 02.12.2018


Ответы (3)


git log — фарфоровая команда.

На самом деле он выполняет довольно разрозненное количество задач — сочетает обход графа ревизий, git diff и git grep и еще много чего.

Сантехнический способ сделать что-то вроде

git log --pretty='[%h] %an: %s' -1 HEAD

состоит в том, чтобы объединить git show-ref с git cat-file и проанализировать результат — что-то вроде

git cat-file commit `git show-ref -s HEAD` |
  while read line; do
    # do some processing
  done

На самом деле корневая справочная страница Git, git(1) — запустите git help git, чтобы прочитать ее, — содержит разбивку команд на слои фарфора и сантехники.

person kostix    schedule 02.12.2018
comment
git cat-file commit <ref> выглядит как надежная установочная команда, но ее вывод сложнее разобрать, чем git log --pretty. Любое лучшее решение? - person iBug; 04.12.2018
comment
Я не вижу, что в нем сложного: это заголовок строк вида ^key SP value LF$, отделенный пустой строкой ^LF LF$ от содержимого. Таким образом, в основном вы читаете все строки до пустой и ищете определенные ключевые слова, такие как author и/или committer. Я имею в виду, не могли бы вы уточнить, какие именно трудности у вас возникли с этим? - person kostix; 04.12.2018
comment
Привет, не могли бы вы взглянуть на мой собственный ответ и дать несколько комментариев? (+1 за ваш ответ) - person iBug; 22.12.2018

Я согласен с kostix; git log — фарфоровая команда. Но проблема здесь в том, что есть некоторые вещи, которые может делать git log, но которые слишком сложно сделать с другими командами, поэтому иногда мы можем заставить git log действовать как водопроводная команда.

Ключевое различие между сантехникой и фарфором проявляется при сравнении, например, git branch и git tag с git for-each-ref или git diff с git diff-tree и git diff-files и git diff-index. Дело не в том, сколько фарфора приходится на сантехнику. Здесь, например, сантехника git for-each-ref имеет две отдельные фарфоровые передние части, а одинарная передняя часть git diff имеет три сантехнических задних конца. Нет, ключ в том, что git diff меняет свое поведение в зависимости от выбранных пользователем элементов конфигурации:

diff.algorithm
diff.dirstat
diff.renameLimit
diff.renames
diff.statGraphWidth
diff.submodule

и так далее. Сантехнические версии игнорируют все пользовательские настройки, поэтому сценарий, который вы пишете, ведет себя одинаково для Алисы, Боба, Кэрол и Дэйва, даже если у них разные настройки.

Используя это определение, мы можем решить, будет ли git log действовать как водопроводная команда. Для этого необходимо перечислить все git log параметры конфигурации. К сожалению, нет простого способа сделать это — в любое время можно добавить дополнительные параметры, а некоторые были добавлены с течением времени.

Вот список, который я нашел, просмотрев руководство git log и git config. Обратите внимание, что я опускаю все ориентированные на различия (например, color.diff и элементы diff.*, упомянутые выше), так как есть вспомогательные команды для обработки эквивалента -p в git log (хотя вы должны работать с одной фиксацией за раз).

color.decorate.<slot>
core.notesRef
format.pretty
i18n.logOutputEncoding
log.abbrevCommit
log.date
log.decorate
log.follow
log.graphColors
log.mailmap
log.showRoot
log.showSignature
notes.displayRef
pretty.<name>

Итак, допустим, мы хотим получить дату коммита из какого-то конкретного коммита, отформатированного определенным образом. Для этого мы можем запустить:

git log --no-walk --pretty=format:%cd

Мы находим в основной документации git log, что красивый формат %cd описывается следующим образом:

%cd: дата коммитера (формат с учетом опции --date=)

Нам не удалось указать параметр --date=, поэтому git log будет искать параметр log.date. Это параметр конфигурации пользователя, и наш вывод git log будет зависеть от выбора пользователя, а не от нашего.

Чтобы заставить эту git log действовать как водопроводную команду, мы должны переопределить настройку конфигурации log.date, например, --date=default или -c log.date=default:

git -c log.date=default log --no-walk --pretty=format:%cd

or:

git log --no-walk --date=default --pretty=format:%cd

В идеале в Git должна быть либо команда plog, определяемая как подходящий вариант git log, либо команда git format-log-metadata, которая принимает --pretty=<directives> параметры и форматирует метаданные журнала. Поскольку это не так, каждый, кто пишет сценарий, которому требуется вывод git log --pretty=format:..., должен убедиться, что он знает о параметрах конфигурации, которые могут на них повлиять.

person torek    schedule 02.12.2018
comment
Означает ли это, что даже если это не строго сантехническая команда, я все равно могу переопределить соответствующие настройки и ожидать результатов сантехники? - person iBug; 04.12.2018
comment
@iBug: Да. Проблема в том, что в будущем, поскольку git log на самом деле фарфоровый, кто-то может добавить новый элемент конфигурации, который вы пока не можете сказать, что должны переопределить, потому что прямо сейчас вы не необходимо переопределить его. - person torek; 04.12.2018
comment
Привет, не могли бы вы взглянуть на мой собственный ответ и дать несколько комментариев? (+1 за ваш ответ) - person iBug; 22.12.2018

Спасибо kostic и torek за их ответы.

Несмотря на то, что они ответили, я считаю, что некоторые параметры красивого формата можно безопасно рассматривать как сантехнику (т. е. безопасные для анализа программами). Примеры включают

  • %H для полной фиксации SHA
  • %T для полного дерева SHA
  • %P для полных родительских SHA
  • %an, %cn, %ae, %ce, %at, %ct для имени автора/коммиттера/адреса электронной почты/даты (Unix). Также время стиля RFC 2822 и ISO 8601 является надежным %aD, %cD, %aI, %cI
  • %s для сводки фиксации
  • %G? для статуса подписи
  • %n для новой строки (смеется...)

Да, хотя на спецификаторы формата, такие как %ad и %cN, могут влиять пользовательские настройки, маловероятно, что указанные выше. Итак, я решил, что мой текущий код, который анализирует вывод git log с красивым форматом, объединенным с приведенными выше спецификаторами, безопасен и не подвержен ошибкам.

person iBug    schedule 22.12.2018
comment
@jthill Чем он отличается от git log? - person iBug; 22.12.2018
comment
У него есть основная команда, известная как гарантии сантехники, и его вывод предназначен для вашего использования. - person jthill; 22.12.2018
comment
Кажется довольно безопасным использовать эти директивы с --pretty={,t}format / --format=, да. Любопытно, что хотя они в основном работают с git rev-list, они не указаны в качестве опций для него. Но rev-list и log создаются из одного и того же исходного файла и в основном обрабатывают одни и те же аргументы. К сожалению, git rev-list ведет себя плохо при использовании с --formats! - person torek; 22.12.2018
comment
@torek Можете ли вы немного рассказать о последнем предложении? Мне очень любопытно, как git rev-list плохо себя ведет с красивыми форматами. - person iBug; 22.12.2018
comment
Просто попробуйте: git log --pretty=format:"%H %cn" HEAD против git rev-list --pretty=format:"%H %cn" HEAD. Конечно, вы можете выкинуть любую вторую строку, но зачем вам это должно? - person torek; 22.12.2018
comment
@torek Мне не сложно сопоставить строку с ^commit [0-9a-f]{40}$, а затем выбросить ее. - person iBug; 22.12.2018
comment
Конечно, но опять же, почему вы должны должны это делать? Это как git for-each-ref печатать дату в каждой второй строке или что-то в этом роде. rev-list — это сантехническая команда; он должен вести себя как один. (Кроме того, если/когда Git переключится на SHA3-256, это {40} будет неправильным.) - person torek; 22.12.2018