Как найти дату коммита git, используя только команды сантехники?

Уже есть вопрос о том, как найти дату коммита в Git. Однако во всех ответах на этот вопрос используются команды git show или git log, которые являются фарфоровыми командами; стандартная мудрость фарфоровых команд, по-видимому, заключается в том, что их формат вывода может измениться, и поэтому по возможности следует избегать их использования в сценариях.

Есть ли способ получить метку времени фиксации git, используя только команды сантехники?


person Pont    schedule 08.10.2018    source источник
comment
Есть ли какая-либо причина требовать команду сантехники, а не просто применять формат к команде фарфора? Например. git log --pretty=format:%aD | head -1 или git show --format="format:%aD" --no-patch HEAD.   -  person pepak    schedule 08.10.2018
comment
@pepak Только то, что, насколько я понимаю, нет гарантии, что эти команды будут продолжать давать идентичный результат в будущих версиях git. Например, git 2.7.4 дает мне Mon, 8 Oct 2018 для даты в формате %aD, но я не знаю, могу ли я разумно ожидать, что какая-то будущая версия не будет давать Mon, 08 Oct 2018 для того же коммита.   -  person Pont    schedule 08.10.2018
comment
Что ж, поскольку формат %aD указан как дата автора, стиль RFC2822, формат должен остаться прежним. Чтобы получить другой фиксированный формат, вы можете использовать %aI или добавить специальный --date=raw. Ни один из них не должен меняться с большей вероятностью, чем сантехническая версия.   -  person pepak    schedule 09.10.2018
comment
@pepak RFC2822 разрешает, но не требует начального нуля, поэтому «стиль RFC2822» не гарантирует ни один из вариантов. Я согласен, маловероятно, что %aI изменится, но поскольку в документации git прямо сказано, что фарфоровые команды могут быть изменены и не должны использоваться в скриптах (за исключением, конечно, случаев, когда они предлагают вариант --porcelain), я бы предпочел не полагаться на предугадывание их будущего развития.   -  person Pont    schedule 09.10.2018


Ответы (3)


Формат объекта фиксации следующий:

tree SP SHA_1_NAME_AS_HEX LF
parent SP SHA_1_NAME_AS_HEX LF
...
author SP any number of words SP <email_addr> SP TIMESTAMP SP TZ_OFFSET LF
committer SP any number of words SP <email_addr> SP TIMESTAMP SP TZ_OFFSET LF
LF
commit message LF
LF
extensive commit message

(Где SP — символ пробела ASCII, 0x20, а LF — символ перевода строки ASCII, 0x0a).

Таким образом, чтобы добиться желаемого, вы:

  1. Звоните git cat-file commit <commitish_of_interest>
  2. Переберите то, что эта программа сбрасывает в свои строки, заканчивающиеся stdout на LF.
  3. Остановитесь на линии, которая начинается с author SP.
  4. Разделите его на пробелы и возьмите последние два поля. Первый - это количество секунд с 00:00 в часовом поясе, определяемом вторым полем, которое имеет формат SHHMM, где S — знак, - или +, который определяет, где смещение, если к западу от или к востоку от Гринвич, соответственно, а HHMM — это смещение часового пояса в HH часах и MM минутах.
  5. Обработайте значения этих двух полей, чтобы отформатировать метку времени.

Обратите внимание, что содержимое полей author и committer одинаково только при "обычных" коммитах. При перебазированных коммитах по крайней мере временные метки могут отличаться, и если коммит был перебазирован лицом, не являющимся автором коммита (его автором), поля будут другими. То же самое верно и для коммитов, созданных из патчей через git am.

person kostix    schedule 08.10.2018

git cat-file -p HASH_OF_COMMIT вернет содержимое большого двоичного объекта фиксации. Таким образом, у вас будет доступ ко всем метаданным и, следовательно, к автору и датам создания.

person Philippe    schedule 08.10.2018

Git немного небрежно относится к правильному различению сантехники и фарфора. Совет использовать вертикальные команды в сценариях хорош, но иногда команда, например git log, не имеет подходящего варианта сантехники, но имеет параметры, которые делают ее "вертикальной", если я могу составить слово.

В этом случае соответствующая команда (отредактирована 21 марта 2019 г., согласно комментарий Джоша):

git -c log.showSignature=false log --pretty=format:%ad --no-walk <hash>

(или то же самое с %cd в качестве директивы формата для даты фиксации; добавьте различные параметры форматирования даты, к самому git log или, например, как %aD, чтобы изменить формат даты). Ничто точно не обещает, что git log может не добавлять новые функции, такие как настройка log.decorate, которые могут нарушить это, и Git должен взять себя в руки и добавить --porcelain опции к командам, которые ведут себя как git status. (Обратите внимание, что git status теперь имеет --porcelain и --porcelain=v2, оба из которых преобразуют его в сантехнику. Не спрашивайте меня, почему это не пишется --plumbing...)

person torek    schedule 08.10.2018
comment
Спасибо. Я заметил параметр --porcelain для status (и для параметра --word-diff, но не для других, для show и log), но, конечно, это просто заставляет меня более опасаться использования фарфоровых команд, которые нет опции --porcelain :). Я предполагаю, что некоторые вещи (например, --pretty=format:%at) вряд ли изменятся, но было бы неплохо иметь это в письменном виде... - person Pont; 09.10.2018
comment
Разработчикам Git было бы легко добавить и сейчас, так как git log --porcelain может означать просто игнорировать настройки log.decorate и ui.color или что-то близкое к этому... (упс, ui.color это Mercurial, color.* для Git Слишком много VCS...) - person torek; 09.10.2018
comment
Это неустойчиво перед лицом необычной пользовательской конфигурации! Если пользователь установил log.showSignature, это также выведет еще несколько строк из gpg, что имеет тенденцию ломать все, что ожидает одну дату. - person Ash; 22.03.2019
comment
@Джош: угу. Итак, git -c log.showSignature=false log --pretty=.... Вот почему git log должен иметь сантехнический эквивалент. - person torek; 22.03.2019