Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to set a git commit to have a timestamp prior to 1970?

Unix timestamps are signed 32 bit integers (64 bit on some systems today, or so I understand). On some software products this allows you to use dates going back as far as 1903 or so.

However, when I try the following:

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

I receive an "fatal: invalid date format" error.

This isn't very practical (I'm not a time-traveler), but I've been wondering about using git for historical purposes. Can this be forced with a git plumbing command? On a related note: does git always use a 32 bit timestamp, or does this depend on the environment it's built on?

like image 866
John O Avatar asked Feb 14 '14 19:02

John O


People also ask

Does git commit have timestamp?

There are actually two different timestamps recorded by Git for each commit: the author date and the commit date. When the commit is created both the timestamps are set to the current time of the machine where the commit was made.

Can GitHub commit backdate?

Yes: multiple projects exist allowing you to generate and push commits "done in the past", in order to update your contribution chart. See for instance contribution.io, github-contribution, or gitgardener. All you need to do, is to push those amended commit on the master branch of your GitHub repo, as I mention here.

How do I commit to a previous date?

To make a commit that looks like it was done in the past you have to set both GIT_AUTHOR_DATE and GIT_COMMITTER_DATE : GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git commit -m '...'


2 Answers

As far back as commit c64b9b8 (git 0.99, May 2005), time has always been referred as

<date>

Date in 'seconds since epoch'

commit 6eb8ae0 defines date as an unsigned long since April 2005.

TLDR;

date before unix epoch can be stored, but cannot be sure to be correctly represented.

But that has evolved since 2014 (see at the end)


Trying to represent a date before has been attempted before: see this thread

The date I'm trying to set is October 4, 1958, that is around timestamp -354808800.

First technique, using the commit --date flags with ISO 8601: it says "invalid date".

Second technique, described in the git ml archive, not using the porcelain:

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

Commit date is effectively updated, but git show clamps the date to zero (Jan 1 1970). tig(1) displays 55 years ago so the actual commit date is properly stored.

Last issue: when trying to push this commit to a remote repository:

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

Finally, when running test-date from git sources:

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

The discussion at the time mentioned:

I am not sure there isn't some unportability at the lowest level.
We freely interchange between time_t and unsigned long in the low-level date code. It probably happens to work because casting the bits back and forth between signed and unsigned types generally works, as long as you end up with the type that you want.
But it isn't necessarily portable, and there can be subtle bugs. See, for example, my recent 9ba0f033.

The good news that this is purely a code problem. The data format is fine. It would just take somebody going through the code and switching all "unsigned long" to "long long" (or time_t, or even "gittime_t" if we want to abstract it).

and fixing the parser algorithm at least in tm_to_time_t()

It is not just "sed s/unsigned long/long long", but rather checking every change to make sure that you aren't introducing new bugs, and that the code correctly handles signed types.
Which is why nobody has done it. ;)


As I mentioned in 2017, in "Use future date while making git commits", Git has started to adopt a different and dedicated timestamp_t type.

As illustrated in Legilibre/Archeo-Lex issue 47:

Dates are now using the timestamp_t type, defined as typedef uintmax_t timestamp_t;, in place of unsigned long type, in order to fix some issues on 32bits platforms... and Windows 64 bits ^^.

The project archeo-lex.fr (which depends on older dates) is using git hash-object, combined with the Git repo viewer Legilibre/Archeo-Lex-web.
This is now (Feb. 2019) done, as commented by Seb35

like image 179
VonC Avatar answered Oct 17 '22 09:10

VonC


Git internally maintains dates as a Unix timestamp and an offset from UTC, so it is not possible to set a commit date before the Unix time epoch.

You must be running a different version of Git than I have on my CentOS 6.5 system (which provides Git 1.7.1), at least yours gives you an error message... If I try to set an impossible commit date using Git 1.7.1, the commit succeeds and silently uses the current time for the commit date; if I try the same operation using a "possible" commit date, it succeeds and records the intended commit date.

like image 3
patbarron Avatar answered Oct 17 '22 11:10

patbarron