9

Let's say I created a project and pushed it to GitHub. When someone clones the project, can they see the file creation time of each file in the project?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
undefined
  • 6,366
  • 12
  • 46
  • 90
  • Let's say you stored the creation date. Then it can be edited, because it is additional data. What value would it have? Short answer is no: they'll see the file creation date on their disk, i.e. the timestamp when the files where created for the first time on that disk. Not on remote disk, not on remote unknown author disk. – Daemon Painter May 27 '20 at 09:29
  • Candidates for the canonical question: *[What's the equivalent of Subversion's "use-commit-times" for Git?](https://stackoverflow.com/questions/1964470/)* (2009) and *[Checking out old files WITH original create/modified timestamps](https://stackoverflow.com/questions/2179722)* (2010). Mercurial has [the Timestamp extension](https://stackoverflow.com/a/7809151) (though that does not help much). – Peter Mortensen Sep 17 '21 at 10:11

3 Answers3

14

They can see the time when a file was added to the repository, via the commit date.

They cannot see the "file creation" or "file modification" timestamps of the file in your local filesystem.

Example

$ git init
Initialized empty Git repository in /tmp/tmp.t4KdOYhQGr/.git/
$ echo bla >file.txt
$ git add file.txt
$ git commit -m 'Added a file'
[master (root-commit) 26b458c] Added a file
 1 file changed, 1 insertion(+)
 create mode 100644 file.txt

Let's look at the commit object:

$ git cat-file -p 26b458c
tree 80717c30ff0d58d079079d2f4d38441035093c49
author mkrieger1 <me@example.email> 1590570496 +0200
committer mkrieger1 <me@example.email> 1590570496 +0200

Added a file

It contains:

  • A reference to a tree object
  • An author with name, email, and timestamp
  • A committer with name, email, and timestamp

These timestamps specify when a commit was first authored, and when it was committed (can be different, e.g. in case of cherry-picking, but here it's the same).

Let's look at the tree object referenced by the commit:

$ git cat-file -p 80717c30ff0d58d079079d2f4d38441035093c49
100644 blob a7f8d9e5dcf3a68fdd2bfb727cde12029875260b    file.txt

It contains a list of blob objects (only a single one in this case), with for each:

  • File permissions
  • A reference to the blob data
  • The name of the blob in the tree

It doesn't contain any timestamps at all. Let's look at the blob object referenced by the tree:

$ git cat-file -p a7f8d9e5dcf3a68fdd2bfb727cde12029875260b
bla

It's just the bare file contents, no timestamps here, either.

Conclusion

The only timestamps that are stored in a Git repository are the "author" and "committer" dates in the commit objects. The tree and blob objects do not contain any timestamps.

There is no timestamp information about the files in the local filesystem contained in the Git repository.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • Can you explain why, please? – undefined May 27 '20 at 09:02
  • So what am I going to see when I check file info? – undefined May 27 '20 at 09:03
  • So, why is the creation date not added? because, in the end, is not relevant. It does not matter, or is not important to know when the file was originally created, because it may happened in another part of the world, and has no practical use I can think of. However, there are some third party options to record such info. See [this answer](https://stackoverflow.com/a/17583212/2125110). There are extensive discussions on why not [here](https://git.wiki.kernel.org/index.php/Git_FAQ#Why_isn.27t_Git_preserving_modification_time_on_files.3F) and [here](https://stackoverflow.com/q/1964470/2125110) – Daemon Painter May 27 '20 at 09:23
  • 1
    Someone decided not to include the metadata about the original file creation/modification time when building the git objects. That's the real reason. – Lasse V. Karlsen May 27 '20 at 09:44
  • It is very unfortunate that git does not offer this at least as an option. It is very relevant when legacy material is imported into a repository. Handling regional time differences already has several solutions, e.g. UTC. – nielsen Apr 26 '21 at 07:36
3

There is no such thing as a file creation time in Git, because there are no files. The repository stores blobs and information about them. When you clone a repository or checkout a branch, that is when some files are created in your worktree and their creation date will be that moment.

Try it yourself. Clone your own remote repository and look at the creation dates of the visible files. They will all be now.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 3
    Indeed, Git does not store the file creation time, but I would argue with the notion that "there are no files". There is a filesystem hierarchy (trees) with directories (more trees), submodules (commits), symlinks (blobs of the right mode) and - yes - files (blobs of mode 644 or 755). – Edward Thomson May 27 '20 at 09:22
2

A quick test shows that, no, the file's timestamps are not preserved.

$ git init a
Initialized empty Git repository in /home/attie/stackoverflow/62039244/a/.git/
$ cd a
$ touch file
$ git add file
$ git ci -m "test"
[master (root-commit) 6cb306d] test
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 file
$ stat file
  File: 'file'
  Size: 0               Blocks: 1          IO Block: 131072 regular empty file
Device: 10000eh/1048590d        Inode: 144982      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   attie)   Gid: ( 1000/   attie)
Access: 2020-05-27 10:01:02.938719777 +0100
Modify: 2020-05-27 10:01:02.938719777 +0100
Change: 2020-05-27 10:01:02.938719777 +0100
 Birth: -
$ cd ..
$ git clone a/.git ./b
Cloning into './b'...
done.
$ cd b
$ stat file
  File: 'file'
  Size: 0               Blocks: 1          IO Block: 131072 regular empty file
Device: 10000eh/1048590d        Inode: 152483      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   attie)   Gid: ( 1000/   attie)
Access: 2020-05-27 10:01:22.494692052 +0100
Modify: 2020-05-27 10:01:22.494692052 +0100
Change: 2020-05-27 10:01:22.494692052 +0100
 Birth: -

By inspecting the commit itself, we can see that the timestamp of both the authorship and commit into the repository are stored, along with the file's type, mode and content hash... none of the underlying ctime / atime / mtime / crtime fields, or any of the rest of struct stat.

$ git cat-file -p HEAD
tree df2b8fc99e1c1d4dbc0a854d9f72157f1d6ea078
author Attie Grande <attie@perdy.attie.co.uk> 1590570072 +0100
committer Attie Grande <attie@perdy.attie.co.uk> 1590570072 +0100

test
$ git cat-file -p df2b8fc99e1c1d4dbc0a854d9f72157f1d6ea078
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    file

You need to be quite careful if you are dealing with the timestamps associated with a file, because in many cases it will not give you the information you might expect.

  1. If the filesystem is mounted with noatime or similar, then opening the file won't necessarily update this timestamp.
  2. If you're using an editor (e.g: vim), then a temporary file may be created when you save which is subsequently moved into place. In this situation all of the timestamps are updated to reflect the new file, the old file's timestamps are not preserved.
  3. Some filesystems don't actually support storage of the creation ("birth") time of a file.
Attie
  • 6,690
  • 2
  • 24
  • 34
  • In your first example, I see that the Access, Modify, and Change are equal, why is that? – undefined May 27 '20 at 09:06
  • Because in the first instance (in `./a/`), `touch` created the file "_at once_"; in the second instance (in `./b/`), `git` created the file. You need to be careful of these values, for a number of reasons, but primarily: A) some filesystems won't store access timestamps (i.e: mounted with `noatime`), and B) some editors will create a new file, and then swap it into place (potentially using the create / birth timestamps) – Attie May 27 '20 at 09:10