threads / bug / 46316

bug report: dates on diff

Subject: bug report: dates on diff

## tl;dr

5 messages between Jul 6, 2017 and Jul 6, 2017.

replies: 4people: 2as markdown or json

Todd Lewis· Jul 6, 2017, 12:54 UTC · lore

I've run into what I think is a bug wrt date handling in "git diff". I have some historical data with which I'm attempting to populate a new git repo with back-dated commits. That appears to work. But referencing those commits by date with "git diff" does not. (I have no idea if the problem is limited to "git diff"; that's just where I've been banging my head.)

I'm using git version 2.9.4.

Below is a recreation of the problem from scratch using made up data. Note that the "git log" output shows the commits with the correct dates, but referencing "master@{any-date-before-git-init}" throws a "Warning: Log for 'master' only goes back to ..." and it erroneously selects the first commit (for 2010 in the example below, instead of the requested 2012 commit).

Here's the terminal session demonstrating the problem:
[utoddl@tarna tmp]$ mkdir gitbug
[utoddl@tarna tmp]$ cd gitbug

[utoddl@tarna gitbug]$ git init Initialized empty Git repository in /tmp/gitbug/.git/

[utoddl@tarna gitbug]$ for year in 2010 2011 2012 2013 2014 ; do
> echo "Charter for year $year." > charter_01-01-$year.txt
> touch -d"$year-01-01" charter_01-01-$year.txt
> done

[utoddl@tarna gitbug]$ ls -al total 20 drwxrwxr-x. 3 utoddl utoddl 160 Jul 6 08:14 . drwxrwxrwt. 19 root root 420 Jul 6 08:12 .. -rw-rw-r--. 1 utoddl utoddl 23 Jan 1 2010 charter_01-01-2010.txt -rw-rw-r--. 1 utoddl utoddl 23 Jan 1 2011 charter_01-01-2011.txt -rw-rw-r--. 1 utoddl utoddl 23 Jan 1 2012 charter_01-01-2012.txt -rw-rw-r--. 1 utoddl utoddl 23 Jan 1 2013 charter_01-01-2013.txt -rw-rw-r--. 1 utoddl utoddl 23 Jan 1 2014 charter_01-01-2014.txt drwxrwxr-x. 7 utoddl utoddl 200 Jul 6 08:12 .git

[utoddl@tarna gitbug]$ for year in 2010 2011 2012 2013 2014 ; do
> cp -p charter_01-01-$year.txt charter.txt
> git add charter.txt
> git commit --date="01-01-$year" -m "Committing charter for $year." charter.txt
> done
[master (root-commit) f5dc22c] Committing charter for 2010.
 Date: Fri Jan 1 07:19:45 2010 -0500
 1 file changed, 1 insertion(+)
 create mode 100644 charter.txt
cp: overwrite 'charter.txt'? y
[master dec8944] Committing charter for 2011.
 Date: Sat Jan 1 07:19:47 2011 -0500
 1 file changed, 1 insertion(+), 1 deletion(-)
cp: overwrite 'charter.txt'? y
[master cab72e0] Committing charter for 2012.
 Date: Sun Jan 1 07:19:48 2012 -0500
 1 file changed, 1 insertion(+), 1 deletion(-)
cp: overwrite 'charter.txt'? y
[master a0cbf74] Committing charter for 2013.
 Date: Tue Jan 1 07:19:49 2013 -0500
 1 file changed, 1 insertion(+), 1 deletion(-)
cp: overwrite 'charter.txt'? y
[master a75164c] Committing charter for 2014.
 Date: Wed Jan 1 07:19:53 2014 -0500
 1 file changed, 1 insertion(+), 1 deletion(-)
[utoddl@tarna gitbug]$ git log
commit a75164cdf56b5f7b10e7575ee4aa4f653656e456
Author: Todd Lewis <utoddl@email.unc.edu>
Date:   Wed Jan 1 07:19:53 2014 -0500
    Committing charter for 2014.
commit a0cbf74320f5b2309f697a48a8026328a998d787
Author: Todd Lewis <utoddl@email.unc.edu>
Date:   Tue Jan 1 07:19:49 2013 -0500
    Committing charter for 2013.
commit cab72e0902cb4130de49c5d898ef4cc2daf1e2d1
Author: Todd Lewis <utoddl@email.unc.edu>
Date:   Sun Jan 1 07:19:48 2012 -0500
    Committing charter for 2012.
commit dec8944f3c411f5f667cdfefee0609d38298489f
Author: Todd Lewis <utoddl@email.unc.edu>
Date:   Sat Jan 1 07:19:47 2011 -0500
    Committing charter for 2011.
commit f5dc22c636dd66a51e74dc01935a4879bd4946d6
Author: Todd Lewis <utoddl@email.unc.edu>
Date:   Fri Jan 1 07:19:45 2010 -0500
    Committing charter for 2010.

[utoddl@tarna gitbug]$ git diff master@{01-01-2012} charter.txt warning: Log for 'master' only goes back to Thu, 6 Jul 2017 08:19:45 -0400.

diff --git a/charter.txt b/charter.txt
index a18dbc9..29fedf9 100644
--- a/charter.txt
+++ b/charter.txt
@@ -1 +1 @@
-Charter for year 2010.
+Charter for year 2014.
[utoddl@tarna gitbug]$
-- 
   +--------------------------------------------------------------+
  / Todd_Lewis@unc.edu  919-445-0091  http://www.unc.edu/~utoddl /
 /      A man's home is his castle, in a manor of speaking.     /
+--------------------------------------------------------------+
Junio C Hamano· Jul 6, 2017, 16:22 UTC · re: Todd Lewis · lore

Re: bug report: dates on diff

Todd Lewis <utoddl@email.unc.edu> writes:
> [utoddl@tarna gitbug]$ git diff master@{01-01-2012} charter.txt
> warning: Log for 'master' only goes back to Thu, 6 Jul 2017 08:19:45 -0400.

What you observed is how <ref>@{<selector>} syntax is designed to work, and is not limited to "git diff". Any Git command e.g. "git rev-parse master@{01-01-2012}", would and should behave the same way.

The thing to note is that the syntax does not pay any attention to author or committer dates recorded in the commit objects. In fact, if you have a ref that points at an object that is not a commit-ish, you can still use the syntax. If you did this, for example

    $ git config core.logallrefupdates always
    $ one=$(echo one | git hash-object --stdin -w)
    $ git update-ref refs/my/blob $one
    ... time passes ...
    $ two=$(echo two | git hash-object --stdin -w)
    $ git update-ref refs/my/blob $two

then "git show my/blob@{2.minutes.ago}" will show the blob object your refs/my/blob ref was pointing at 2 minutes ago.

And as you may know, blobs do not record any timestamp. So how does this work?

The reason why this works is because the time in <ref>@{$time} syntax is about asking what was pointed by the <ref> back in $time in your repository. It does not matter what timestamp the object that was pointed by the <ref> has (or does not have).

If you didn't create this repository back in 2012, then the syntax "master@{01-01-2012}" that asks "Back at the beginning of 2012, what object did the master branch point at?" does not have a sensible answer. That can be seen in the warning you got from Git.

Hope this clarifies.
Todd Lewis· Jul 6, 2017, 17:32 UTC · re: Junio C Hamano · lore

Re: bug report: dates on diff

On 07/06/2017 12:22 PM, Junio C Hamano wrote:
Show 6 quoted lines
> If you didn't create this repository back in 2012, then the syntax
> "master@{01-01-2012}" that asks "Back at the beginning of 2012, what
> object did the master branch point at?" does not have a sensible
> answer.  That can be seen in the warning you got from Git.
> 
> Hope this clarifies.
Thanks; it does explain what I saw, and even makes some sense.

However, it does leave me scratching my head about how to accomplish what I set out to do, or just how to reference commits by their dates as displayed by git log w/o either changing the system time/date when committing historic data (which seems like a total no-no), or making multiple passes over "get log" to determine how to ref. Perhaps there's a way to patch the log to match dates recorded in relevant objects?

Trying not to sound snide, but, what's the point of "--date=" on commits if you can't use it later? Granted, things always seem harder until you understand how the work. Thanks again.

Junio C Hamano· Jul 6, 2017, 18:03 UTC · re: Todd Lewis · lore

Re: bug report: dates on diff

Todd Lewis <utoddl@email.unc.edu> writes:
> Trying not to sound snide, but, what's the point of "--date=" on commits if you
> can't use it later? Granted, things always seem harder until you understand how
> the work. Thanks again.
You do not sound snide at all, at least to me ;-)
Imagine this scenario:
 - Contributor A writes a change on 2017-07-01 and send it in to me
 - Contributor B writes a change on 2017-07-03 and send it in to me
 - I apply change from B on 2017-07-04 on 'master'
 - I apply change from A on 2017-07-05 on 'master'
 - You clone the resulting repository from me on 2017-07-06

Now, you have at the tip of 'master' in your repository the commit that records the change by contributor A.

And there are three times that are relevant to your tip of 'master'.
 - When was the commit that sits at the tip of 'master' made?
 - When was the change recorded in that commit made?
 - When was the commit made at the tip of _your_ 'master'?

and the answers are 2017-07-01, 2017-07-05 and 2017-07-06, respectively. They are called "committer", "author" and "reflog" timestamps.

The 'master@{<time>}' syntax is about the reflog timestamp. It never looks at the former two. In general whenever you see <ref>@{...}, that is talking about the information that is stored in "reflog", the record of when and in what order the <ref> in _your_ repository pointed at various objects.

The "commit --date=<time>" is about tweaking the "author" timestamp the commit records. It does not affect the "committer" timestamp. By definition (of what "reflog" is), it will not affect the reflog timestamp, because the reflog timestamp for a particular commit would be different across repositories. I had A's commit on _my_ master on 2017-07-05, but the time you had it on _your_ master was not until 2017-07-06.

I think the best way to do this properly would be to extend the "<ref>^{...}" syntax so that we can say e.g.

    git show "master^{#author-time > 2017-01-01}"

to mean "traverse from the tip of 'master' and find the first commit that satisfies the given expression, "author-time > 2017-01-01", i.e. has author timestamp that is later than the specified date. Which would be in line with the existing

    git show "master^{/my commit message}"

that means "traverse from the tip of 'master' and find the first commit that has 'my commit message' in the log message".

Note that "git log --since=<time> --until=<time> master" would be the thing that is closest to what you would want that already exists, but that limits by the "committer" timestamp. You _could_ lie about both author and committer timestamp when building the backdated history and use this mechanism, but we have author and committer timestamps that are distinct for a reason, so it is a rather poor workaround.

Junio C Hamano· Jul 6, 2017, 18:05 UTC · re: Junio C Hamano · lore

Re: bug report: dates on diff

Junio C Hamano <gitster@pobox.com> writes:
Show 19 quoted lines
> Imagine this scenario:
>
>  - Contributor A writes a change on 2017-07-01 and send it in to me
>  - Contributor B writes a change on 2017-07-03 and send it in to me
>  - I apply change from B on 2017-07-04 on 'master'
>  - I apply change from A on 2017-07-05 on 'master'
>  - You clone the resulting repository from me on 2017-07-06
>
> Now, you have at the tip of 'master' in your repository the commit
> that records the change by contributor A.
>
> And there are three times that are relevant to your tip of 'master'.
>
>  - When was the commit that sits at the tip of 'master' made?
>  - When was the change recorded in that commit made?
>  - When was the commit made at the tip of _your_ 'master'?
>
> and the answers are 2017-07-01, 2017-07-05 and 2017-07-06, respectively.
> They are called "committer", "author" and "reflog" timestamps.

Oops, obviously the dates have to be 2017-07-05, 2017-07-01 and 2017-07-06. I made the commit on the 5th (i.e. "committer" timestamp) that records a change written on the 1st (i.e. "author" timestamp).

← back to recent threads