gitgit-index

What is ctime and mtime used for in the git index?


When a file is added to the index for the first time the file’s create timestamp is stored in the index record's ctime and the file's current modified time stamp is stored in the mtime field.

When the file is added after a change, the mtime is updated with the current timestamp of the file.

When the file is checked out it does not use the mtime for the What are these timestamps used for in the world of git?

Looking at references to the index they just seem to be there. Maybe they had some future purpose that was never realized?

$ git ls-files --debug readme.txt
readme.txt
  ctime: 1531246924:79161700
  mtime: 1531258019:669963000
  dev: 0        ino: 0
  uid: 0        gid: 0
  size: 13      flags: 0

Solution

  • The index has three names: "the index" (the one you used here), the staging-area (which is better in some sense as it describes its function), and the cache. It's the last name that applies here.

    What makes the index an index or cache, as opposed to just a staging area, is that it indexes and caches the contents of the work-tree. The point of caching is to speed things up. But caches invariably have a problem: at some point, some or all of the data in the cache becomes invalid. The cache, which provides fast/short-cut access to the real, actual, correct data, no longer reflects reality. The cache must be discarded or refilled with correct data.

    Now, Git's index holds a copy of the file that is, or at least was at git checkout time, in the work-tree.1 If you have changed the file in some way, how is Git going to know that the cached copy is invalid?

    Git's answer is to store, along with the cached copy, some of the stat information about that file, including the file's size and the two time stamps you observed. If you modify the file in some way—even to the extent of just changing its mode, which does not touch the file's contents (so the size and mtime remain unchanged)—the ctime timestamp will be updated, and Git will know that something has changed. Of course if you modify the contents or change the size, Git will also know.


    1Technically the index holds a cleaned copy of the file, ready to commit. If you have end-of-line settings and/or smudge and/or clean filters, the cleaned copy may not actually match the work-tree copy.


    You noted that:

    When the file is checked out it does not use the mtime for the [unfinished thought here]

    I think what you have observed is one of Git's other optimizations. If you run git checkout <commit-specifier> in an empty situation (e.g., the first checkout of a clone operation), Git has to completely populate the index and work-tree for the first time. Once you have done that, though, if you now run a different git checkout to check out some other commit, Git can optimize the checkout:

    As a result, the mtime of files that are the same between the two commits, in the work-tree, remains unchanged, because those files have not been touched at all.

    This is just yet another aspect of the cache doing its caching. However, it does play into the ability to switch branches while carrying some modifications around in your index and/or work-tree. For details, see Checkout another branch when there are uncommitted changes on the current branch.