Можно ли установить для коммита git отметку времени до 1970 года?

Временные метки Unix представляют собой 32-битные целые числа со знаком (64-битные сегодня в некоторых системах, насколько я понимаю). В некоторых программных продуктах это позволяет использовать даты, начиная с 1903 года или около того.

Однако, когда я пытаюсь сделать следующее:

git commit -m "this is a test commit" --date="1960-04-07 18:00:00"

Я получаю сообщение об ошибке «фатальный: неверный формат даты».

Это не очень практично (я не путешественник во времени), но мне было интересно использовать git для исторических целей. Можно ли это сделать с помощью команды git plumbing? В связи с этим: всегда ли git использует 32-битную временную метку или это зависит от среды, в которой он построен?


person John O    schedule 14.02.2014    source источник
comment
На самом деле, если бы это сработало, это было бы очень практично для некоторых людей, пытающихся поместить код закона в систему управления версиями, например этого репозитория   -  person autra    schedule 29.04.2018


Ответы (4)


Еще в commit c64b9b8 (git 0.99, май 2005 г.) время всегда было упоминается как

<date>

Дата в секундах с эпохи'

фиксация 6eb8ae0 определяет дату как unsigned long с апреля 2005 года.

TLDR;

дата до эпохи unix может быть сохранена, но не может быть уверена, что она будет правильно представлена.

Но это изменилось с 2014 года (см. в конце)


Попытка представить дату до предпринималась ранее: см. эта тема

Дата, которую я пытаюсь установить, — 4 ​​октября 1958 года, то есть около метки времени -354808800.

Первый метод, используя флаги фиксации --date с ISO 8601: он говорит «invalid date».

Второй метод, описанный в архиве git ml, не с помощью фарфора:

git commit
git cat-file -p HEAD > tmp.txt
# at this point, edit the file to replace the timestamp

git hash-object -t commit -w tmp.txt
#=> 2ee8fcc02658e23219143f5bcfe6f9a4615745f9
git update-ref -m 'commit: foo' refs/heads/master \
    2ee8fcc02658e23219143f5bcfe6f9a4615745f9

Дата фиксации эффективно обновляется, но git show фиксирует дату до нуля (Jan 1 1970). tig(1) отображает 55 years ago, поэтому фактическая дата фиксации сохраняется правильно.

Последняя проблема: при попытке отправить эту фиксацию в удаленный репозиторий:

#=> remote: error: object 2ee8fcc02658e23219143f5bcfe6f9a4615745f9:invalid
#       author/committer line - bad date
#=> remote: fatal: Error in object
#=> error: unpack failed: index-pack abnormal exit

Наконец, при запуске test-date из исходников git:

./test-date show -354808800
#=> -354808800 -> in the future

В обсуждении в то время упоминалось:

Я не уверен, что на самом низком уровне нет непереносимости.
Мы свободно переключаемся между time_t и unsigned long в низкоуровневом коде даты. Вероятно, это сработает, потому что переключение битов между подписанными и беззнаковыми типами обычно работает, если вы в конечном итоге получаете нужный тип.
Но это не обязательно переносимо, и могут быть тонкие ошибки. . См., например, мой недавний 9ba0f033.

Хорошая новость в том, что это чисто проблема с кодом. Формат данных в порядке. Просто кто-то просматривает код и переключает все «unsigned long» на «long long» (или time_t, или даже «gittime_t», если мы хотим абстрагироваться).

и исправление алгоритма парсера хотя бы в tm_to_time_t()

Это не просто "sed s/unsigned long/long long", а проверка каждого изменения, чтобы убедиться, что вы не добавляете новых ошибок и что код правильно обрабатывает подписанные типы.
Вот почему никто этого не сделал. Это. ;)


Как я упоминал в 2017 году, в статье «Использовать будущую дату при совершении коммитов git" Git начал использовать другой и специализированный timestamp_t тип.

Как показано в Legilibre/Archeo-Lex, выпуск 47:

Даты теперь используют тип timestamp_t, определенный как typedef uintmax_t timestamp_t;, вместо типа unsigned long, чтобы исправить некоторые проблемы на 32-битных платформах... и 64-битных Windows ^^.

В проекте archeo-lex.fr (который зависит от более старых дат) используется git hash-object в сочетании с средство просмотра репозитория Git Legilibre/Archeo-Lex-web.
Сейчас (февраль 2019 г.) это сделано , как прокомментировано пользователем Seb35

person VonC    schedule 27.07.2014
comment
Спасибо. Я использую это, чтобы поместить французский закон в Git на archeo-lex.fr. В репозиториях указаны даты до 1970 г. (1803 г. для старшего, Гражданский кодекс) и после 2100 г. Обратите внимание, что GitHub и Gitlab отклоняют репозитории. Код Python, создающий репозитории здесь. Я также адаптировал веб-интерфейс PHP, см. эту фиксацию. Я также повеселился со старыми часовыми поясами, потому что в 1803 году их не существовало. - person Seb35; 10.02.2019
comment
@Seb35 Отлично! Я включил ссылку на ваш комментарий в ответ для большей наглядности. - person VonC; 10.02.2019
comment
@ Seb35 Это довольно круто. Существуют ли какие-либо стандарты даже для того, как использовать git для уставов/законодательства? В США, когда закон отменяется, это не означает, что текст удаляется, он как бы комментируется законом, отменяющим его. Было бы странно видеть Конституцию без 18-й поправки... - person John O; 06.11.2019
comment
@JohnO Это расходится с исходным вопросом. Я не знаю стандартов для Git в этом случае использования, он все еще экспериментальный, но я знаю, что он также экспериментировал с китайской конституцией. Вопрос об отмененных текстах является юридическим вопросом, а не техническим, вы можете прочитать об операции консолидации, но, похоже, она обычно не используется для Конституции США. - person Seb35; 06.11.2019

Git внутренне поддерживает даты в виде метки времени Unix и смещения от UTC, поэтому невозможно установить дату фиксации раньше эпохи времени Unix.

Вы должны использовать версию Git, отличную от моей, в моей системе CentOS 6.5 (которая предоставляет Git 1.7.1), по крайней мере, ваша выдает сообщение об ошибке... Если я попытаюсь установить невозможную дату фиксации с помощью Git 1.7. 1, фиксация завершается успешно, и в качестве даты фиксации используется текущее время; если я попытаюсь выполнить ту же операцию, используя «возможную» дату фиксации, она преуспеет и запишет предполагаемую дату фиксации.

person patbarron    schedule 14.02.2014
comment
Временная метка unix представляет собой 32-битное целое число со знаком. Отрицательные числа соответствуют, как можно было бы подумать, и, поскольку вы получаете 2,5 миллиарда из них, а 2 миллиарда секунд составляют примерно 64 года, вы должны быть в состоянии вернуться в 1906 год плюс изменение. Или я так понимаю. Что-нибудь даже использует беззнаковое целое число для временных меток? - person John O; 15.02.2014
comment
Глядя в исходный код, кажется, что дата коммита записана в структуре коммита как unsigned long: github.com/git/git/blob/master/commit.h - person patbarron; 15.02.2014
comment
И я признаю, я никогда не думал об идее подписания time_t, что означает, что даты до эпохи могут быть представлены, так что технически это может показаться ошибкой в ​​​​Git (или, по крайней мере, неточностью документации... .) - person patbarron; 15.02.2014

Вы можете сохранить их, но ничто не покажет их так, как вы ожидали (пока).

Внутренний формат Git хранит данные фиксации в виде числовой строки. например.:

$ git cat-file -p aa2706463fdeb51d6f9d0e267113b251888cf7f5
...
author Junio C Hamano <[email protected]> 1383318892 -0700
committer Junio C Hamano <[email protected]> 1383318892 -0700

Я не считаю, что требуется, чтобы это число было положительным. Однако большинство реализаций, включая git, анализируют его как число без знака и не отображают эти даты правильно. Например, в builtin/blame.c:

    *time = strtoul(ident.date_begin, NULL, 10);

Так; использование отрицательного времени — это не то, что вы можете легко сделать с помощью текущих инструментов или отобразить с помощью текущих инструментов, но модель Git означает, что коммиты, включающие их, останутся неизменными в репозитории.

person Joe    schedule 15.02.2014

Я просто повозился с git hash-object и создал следующий коммит-объект:

tree 5efb9bc29c482e023e40e0a2b3b7e49cec842034
author x <[email protected]> -134607600 -0500
committer z <[email protected]> 1402404632 -0600

blah blah

Вы заметите, что дата автора установлена ​​на отрицательное число. Затем я использовал git update-ref, чтобы попытаться связать объект фиксации в... не повезло, я получаю следующий вывод, когда делаю журнал git:

$ git log
commit 2303e7012001a3cc1c3dec806d0902008e1257a8
Author: x <[email protected]>
Date:   (null)

    blah blah

Sourcetree так же запутался:

Parents: 
Author: x <[email protected]>
Date: Monday, January 01, 0001 12:00:00 AM
Committer: z <[email protected]>
Commit Date: Tuesday, June 10, 2014 7:50:32 AM

(Кажется, я забыл включить родительский объект фиксации...)

Точно так же даты в далеком будущем также не работают (указывая на то, что это, вероятно, не обрабатывается как 64-битное значение, даже если оно одно).

Я не уверен, квалифицируется ли этот ответ как «нет, вы не можете этого сделать» или «вы можете, но это не работает». Потребуется модифицированный клиент, чтобы иметь возможность видеть журналы git с правильными датами, что устраняет любые возможные преимущества для этого. Если кто-то знает изящную команду git log, которая будет правильно анализировать эти временные метки (они исчезли в этот момент?!?!), пожалуйста, поправьте меня.

person John O    schedule 14.02.2014