Можно ли установить фиксацию 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-битную метку времени, или это зависит от среды, на которой она построена?

Ответ 1

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

<date>

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

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

TL;DR;

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


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

Дата, которую я пытаюсь установить, - это 4 октября 1958 года, которая находится вокруг timestamp -354808800.

Первый метод, используя флаги commit --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", а проверка всех изменений, чтобы убедиться, что вы не вводите новые ошибки, и что код правильно обрабатывает подписанные типы.
Вот почему никто этого не сделал.;)

Ответ 2

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

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

Ответ 3

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

Внутренний формат 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 означает, что коммиты, включая их, останутся неизменными в репозитории.

Ответ 4

Я просто сменил хэш-объект git и создал следующий объект фиксации:

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

blah blah

Вы заметите, что дата автора установлена ​​на отрицательное число. Затем я использовал git update-ref, чтобы попытаться связать объект commit в... не повезло, я получаю следующий вывод, когда я делаю журнал 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, которая будет правильно анализировать эти временные метки (они ушли в этот момент?!?!), Пожалуйста, поправьте меня.