Working with dates in Git

When working in git, you most commonly trace a repository’s history using commits’ SHA-1 hashes. To revert to a previous commit, you might write something like this:

$ git revert 883c3dc85a49d98da649

The problem is, we tend not to think in hashes. Rather, we wonder what changes we made yesterday, or remember that a now-broken piece of code worked perfectly a week ago. Although we can use git log to track down the commit we want, there has to be an easier way. Luckily git understands our human quirks, and offers us just that.

Understanding dates in Git: author date vs. committer date & ‘approxidate’

There are two kinds of timestamp in git: a GIT_AUTHOR_DATE and a GIT_COMMITTER_DATE. Although in most cases they both store the same value, they serve slightly different purposes. As the Pro Git Book explains:

The author is the person who originally wrote the work, whereas the committer is the person who last applied the work.

So if, for instance, you send in a patch to a project, the author date will be when you made the original commit but the committer date will be when the patch was applied. Another common scenario is rebasing: rebasing will alter the commit date, but not the author date.

This distinction is worth mentioning because of an inconsistency in git that Carl Worth points out:

By default, git log displays author dates as “Date” but then uses commit dates when given a --since option. That seems like broken defaults to me.

In other words, all the methods listed below rely on the committer date, even though you’re used to seeing the author date. As mentioned, most of the time they’ll be the same, but to see committer dates in the log just use:

$ git log --format=fuller

Date parsing with ‘approxidate’

Git employs a kind of date parsing which will be familiar to any rubyists who’ve used Chronic. The parser, called ‘approxidate’ is very flexible, and allows both fixed dates in any format you can dream up (“10-11-1998”, “Fri Jun 4 15:46:55 2010 +0200”, “9/9/83”) and relative dates (“today”, “1 month 2 days ago”, “six minutes ago”). You can include days of the week (“last Tuesday”), timezones (“3PM GMT”) and ‘named’ times (“noon”, “tea time”).

Approxidate isn’t really documented anywhere, but the code for the parser is very readable, so check it out to get an idea of the kind of formats git will accept.

log, whatchanged, —since and —until

OK, so how about if we want to look at all the commits made since yesterday? All we need is the --since option:

$ git log --since="yesterday"

We can also use --until to fetch all commits up to a certain date; or of course we can use both options in tandem:

$ git log --since="1 week ago" --until="yesterday"

--since and --until can also be used with whatchanged.

$ git whatchanged --since="1/1/2010"

Worth noting: instead of --until and --since you can use --before and --after, if that’s more your style.

revert, diff and the @ construct

Not all git commands have options like --since and --until. So what if we wanted to revert back to our repo as it was a month ago? Luckily git provides us with a more generic way to reference commits using dates, with the @ construct:

$ git revert master@{"1 month ago"}

(where master is the name of the branch you’re working on).

This lets us do clever things, like:

$ git diff master@{"yesterday"} master@{"1 year 6 months ago"}

which will compare the repo as it was yesterday, and as it was 1 year, 6 months ago.

Change history: amending and editing dates


There might be certain situations where you want to alter the timestamps git assigns to commits. There are a couple of ways that you can do this.

Use --date

The --date option allows you to specify the author date that git attaches to the commit. Here we can’t use approxidate unfortunately, only fixed dates will work (YYYY.MM.DD, MM/DD/YYYY, DD.MM.YYYY, RFC 2822 and ISO 8601 are all valid).

$ git commit --date="Wed Feb 16 14:00 2037 +0100"

We can also use amend to change the timestamp of a previous commit:

$ git commit --amend --date="Wed Feb 16 14:00 2037 +0100"

Unfortunately --date will only change the GIT_AUTHOR_DATE, not GIT_COMMITTER_DATE. If this is a problem, you may need to…

Manually set GIT_AUTHOR_DATE and GIT_COMMITTER_DATE

A word of warning - overriding GIT_COMMITER_DATE is somewhat frowned upon:

It should be never overridden, unless you know you absolutely need to override it (to ensure the commit gets the same ID as another or when migrating history around)

$ export GIT_AUTHOR_DATE="Wed Feb 16 14:00 2037 +0100"
$ export GIT_COMMITTER_DATE="Wed Feb 16 14:00 2037 +0100"
$ git commit

The code above will alter both timestamps. Amending a commit in the past is more tricky, but the GitFAQ provides us with a handy bash script:

#!/bin/sh
#
# Rewrite all branches to modify the date of one specific commit in a repo.
#
# Sample date format: Fri Jan 2 21:38:53 2009 -0800
# ISO8601 and RFC822 dates will also work.
#
# Note: filter-branch is picky about the commit argument. As of 1.7.0.4,
# a hex ID will work, the symbolic revision HEAD will fail silently,
# and the usability of more exotic rev specs was not tested by the author.
#
# Copyright (c) Eric S. Raymond, 2010-08-01. BSD terms apply (if anybody really thinks that this
# script is long and non-obvious enough to fall under copyright law).
#
commit="$1"
date="$2"
git filter-branch --env-filter \
    "if test \$GIT_COMMIT = '$commit'
     then
         export GIT_AUTHOR_DATE
         export GIT_COMMITTER_DATE
         GIT_AUTHOR_DATE='$date'
         GIT_COMMITTER_DATE='$date'
     fi" &&
rm -fr "$(git rev-parse --git-dir)/refs/original/"

Instead of setting the date explicitly, we can also use GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" ( source: this gist ) to match up the committer date to the author date.


U
ufocoder
0 points
10 years ago

I wrote Github Contributions table Writer. There's a just for fun python script, It show you how previsions commit date could be pixel brush for your contributions table of your Github account, URL https://github.com/ufocoder...

?
Anonymous
0 points
7 years ago

I know it's an example but the 16th of February 2037 is a Monday not a Wednesday :D

S
Stefan Marchhart
0 points
8 years ago

How would I undo editing the COMMITTER_DATE or AUTHOR_DATE variables, and let git go back to setting dates automatically?

M
MM
0 points
8 years ago

unset GIT_COMMITTER_DATE GIT_AUTHOR_DATE

S
Steven Leggett
0 points
11 years ago

Super useful to see what has been merged:
git log --since="yesterday" |grep "Merge pull"

?
Anonymous
0 points
12 years ago

I am attempting to use

git commit --date="2004.07.14"

I get the error message "fatal: Invalid date format: 2004.07.14"

My git version is 1.7.11.mysysgit.1

What am I doing wrong?

P
Peter Bartels
0 points
12 years ago

git commit --date="2004.07.14 13:00"

V
Valdis Vitayaudom
0 points
13 years ago

+1

T
Thomas Ferris Nicolaisen
0 points
14 years ago

Thanks for the info on approxidate. Google wasn't being very helpful in finding any info on how git dates work, so this post was of big help!

D
derp_cookies
0 points
10 years ago

Note that the "@{"1 year ago"}" style relies on your REFLOGS. If your reflogs are garbage collected after 30 days, then you can't go past 30 days using this method.

S
sdlins
0 points
14 years ago

Really good. Thanks from a brazillian guy.

M
muman613
0 points
10 years ago

How much is a brazillian?

S
sdlins
0 points
10 years ago

Any person is more valuable than parents that let your child grow up unloved!

B
Binh Thanh Nguyen
0 points
11 years ago

thanks, nice post

M
Michael Radionov
0 points
7 years ago

Very useful article, thanks

?
Anonymous
0 points
11 years ago

git revert does not equal svn revert. What you are trying to do there is "git checkout <revision>". git revert <revision> creates opposite changes that revert the given commits changes - when trying to "revert to given revision" you definitely do not want to modify your codebase.

S
skierpage
0 points
13 years ago

Very helpful. Is there a way to get diff to use the modification date of a file as the AUTHOR_DATE when you commit that one file?  I had saved a bunch of variants of myfile as myfile_bak, myfile_2010, etc. and wanted to store the version history in git. I manually set --date= as I committed each one, but it seems there should be an easier way. You can get the modified time using ls and cut shell-foo, so something like

git commit --date="ls -l --time-style=full-iso myfile | cut -c 26-44" myfile

should work.

S
Seksuolog Online
0 points
4 years ago

good post. Thanks for share

J
jianhong yu
0 points
10 months ago

ok, it is good diea https://www.hsd-jet.com

I
ivoryxiong
0 points
11 years ago

nice post, it helps me a lot, thank you!

E
e-seksuolog.pl
0 points
3 years ago

Great post. Thanks for share

M
Mój Seksuolog
0 points
4 years ago

This is what i was looking for. Very useful article. Thanks for share!

H
Hishine
0 points
5 years ago

I used git log --since="yesterday" |grep "Merge pull" to make it working, thanks anyway