Search code examples
gitscriptinggit-plumbing

How do I find the date of a git commit using only plumbing commands?


There is already a question asking how to find the date of a commit in Git. However, all the answers to that question make use of the git show or git log commands, which are both porcelain commands; the standard wisdom on porcelain commands seems to be that their output format may change and that using them in scripts should therefore be avoided wherever possible.

Is there a way to obtain the timestamp of a git commit using only plumbing commands?


Solution

  • The format of a commit object is as follows:

    tree SP SHA_1_NAME_AS_HEX LF
    parent SP SHA_1_NAME_AS_HEX LF
    ...
    author SP any number of words SP <email_addr> SP TIMESTAMP SP TZ_OFFSET LF
    committer SP any number of words SP <email_addr> SP TIMESTAMP SP TZ_OFFSET LF
    LF
    commit message LF
    LF
    extensive commit message
    

    (Where SP is an ASCII space character, 0x20, and LF is an ASCII line-feed character, 0x0a).

    So basically to achieve what you want, you:

    1. Call git cat-file commit <commitish_of_interest>
    2. Iterate over what that program dumps to its stdout by LF-terminated lines.
    3. Stop at the line which starts with author SP.
    4. Split it on spaces, and take the last two fields. The first one is the number of seconds since 00:00 in the timezone defined by the second field, which has the format SHHMM where S is a sign, - or +, whcih defines where the offset if to the West of, or to the East of Greenwich, correspondingly, and HHMM is the offset, in HH hours and MM minutes, of the timezone.
    5. Process the values of these two fields to format the timestamp.

    Note that the contents of the author and committer fields are the same only on "normal" commits. On rebased commits at least timestamps may differ, and if a commit was rebased by a person other than who actually authored the commit (its author), the fields will be different. The same is also true for commits created from patches via git am.