{"thread":{"id":"46316","subject":"bug report: dates on diff","startedAt":"2017-07-06T12:54:26Z","lastAt":"2017-07-06T18:05:52Z","messageCount":5,"participants":["Todd Lewis","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"323891","messageId":"b28bc109-b06f-0acf-960b-0b6761b0ee38@email.unc.edu","threadId":"46316","inReplyTo":null,"subject":"bug report: dates on diff","fromName":"Todd Lewis","fromEmail":"utoddl@email.unc.edu","sentAt":"2017-07-06T12:54:14Z","receivedAt":"2017-07-06T12:54:26Z","isPatch":false,"sender":{"key":"utoddl@email.unc.edu","avatar":null},"body":"I've run into what I think is a bug wrt date handling in \"git diff\". I have some\nhistorical data with which I'm attempting to populate a new git repo with\nback-dated commits. That appears to work. But referencing those commits by date\nwith \"git diff\" does not. (I have no idea if the problem is limited to \"git\ndiff\"; that's just where I've been banging my head.)\n\nI'm using git version 2.9.4.\n\nBelow is a recreation of the problem from scratch using made up data. Note that\nthe \"git log\" output shows the commits with the correct dates, but referencing\n\"master@{any-date-before-git-init}\" throws a \"Warning: Log for 'master' only\ngoes back to ...\" and it erroneously selects the first commit (for 2010 in the\nexample below, instead of the requested 2012 commit).\n\nHere's the terminal session demonstrating the problem:\n\n[utoddl@tarna tmp]$ mkdir gitbug\n\n[utoddl@tarna tmp]$ cd gitbug\n\n[utoddl@tarna gitbug]$ git init\nInitialized empty Git repository in /tmp/gitbug/.git/\n\n[utoddl@tarna gitbug]$ for year in 2010 2011 2012 2013 2014 ; do\n> echo \"Charter for year $year.\" > charter_01-01-$year.txt\n> touch -d\"$year-01-01\" charter_01-01-$year.txt\n> done\n\n[utoddl@tarna gitbug]$ ls -al\ntotal 20\ndrwxrwxr-x.  3 utoddl utoddl 160 Jul  6 08:14 .\ndrwxrwxrwt. 19 root   root   420 Jul  6 08:12 ..\n-rw-rw-r--.  1 utoddl utoddl  23 Jan  1  2010 charter_01-01-2010.txt\n-rw-rw-r--.  1 utoddl utoddl  23 Jan  1  2011 charter_01-01-2011.txt\n-rw-rw-r--.  1 utoddl utoddl  23 Jan  1  2012 charter_01-01-2012.txt\n-rw-rw-r--.  1 utoddl utoddl  23 Jan  1  2013 charter_01-01-2013.txt\n-rw-rw-r--.  1 utoddl utoddl  23 Jan  1  2014 charter_01-01-2014.txt\ndrwxrwxr-x.  7 utoddl utoddl 200 Jul  6 08:12 .git\n\n[utoddl@tarna gitbug]$ for year in 2010 2011 2012 2013 2014 ; do\n> cp -p charter_01-01-$year.txt charter.txt\n> git add charter.txt\n> git commit --date=\"01-01-$year\" -m \"Committing charter for $year.\" charter.txt\n> done\n[master (root-commit) f5dc22c] Committing charter for 2010.\n Date: Fri Jan 1 07:19:45 2010 -0500\n 1 file changed, 1 insertion(+)\n create mode 100644 charter.txt\ncp: overwrite 'charter.txt'? y\n[master dec8944] Committing charter for 2011.\n Date: Sat Jan 1 07:19:47 2011 -0500\n 1 file changed, 1 insertion(+), 1 deletion(-)\ncp: overwrite 'charter.txt'? y\n[master cab72e0] Committing charter for 2012.\n Date: Sun Jan 1 07:19:48 2012 -0500\n 1 file changed, 1 insertion(+), 1 deletion(-)\ncp: overwrite 'charter.txt'? y\n[master a0cbf74] Committing charter for 2013.\n Date: Tue Jan 1 07:19:49 2013 -0500\n 1 file changed, 1 insertion(+), 1 deletion(-)\ncp: overwrite 'charter.txt'? y\n[master a75164c] Committing charter for 2014.\n Date: Wed Jan 1 07:19:53 2014 -0500\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\n[utoddl@tarna gitbug]$ git log\ncommit a75164cdf56b5f7b10e7575ee4aa4f653656e456\nAuthor: Todd Lewis <utoddl@email.unc.edu>\nDate:   Wed Jan 1 07:19:53 2014 -0500\n\n    Committing charter for 2014.\n\ncommit a0cbf74320f5b2309f697a48a8026328a998d787\nAuthor: Todd Lewis <utoddl@email.unc.edu>\nDate:   Tue Jan 1 07:19:49 2013 -0500\n\n    Committing charter for 2013.\n\ncommit cab72e0902cb4130de49c5d898ef4cc2daf1e2d1\nAuthor: Todd Lewis <utoddl@email.unc.edu>\nDate:   Sun Jan 1 07:19:48 2012 -0500\n\n    Committing charter for 2012.\n\ncommit dec8944f3c411f5f667cdfefee0609d38298489f\nAuthor: Todd Lewis <utoddl@email.unc.edu>\nDate:   Sat Jan 1 07:19:47 2011 -0500\n\n    Committing charter for 2011.\n\ncommit f5dc22c636dd66a51e74dc01935a4879bd4946d6\nAuthor: Todd Lewis <utoddl@email.unc.edu>\nDate:   Fri Jan 1 07:19:45 2010 -0500\n\n    Committing charter for 2010.\n\n[utoddl@tarna gitbug]$ git diff master@{01-01-2012} charter.txt\nwarning: Log for 'master' only goes back to Thu, 6 Jul 2017 08:19:45 -0400.\ndiff --git a/charter.txt b/charter.txt\nindex a18dbc9..29fedf9 100644\n--- a/charter.txt\n+++ b/charter.txt\n@@ -1 +1 @@\n-Charter for year 2010.\n+Charter for year 2014.\n[utoddl@tarna gitbug]$\n\n-- \n   +--------------------------------------------------------------+\n  / Todd_Lewis@unc.edu  919-445-0091  http://www.unc.edu/~utoddl /\n /      A man's home is his castle, in a manor of speaking.     /\n+--------------------------------------------------------------+\n"},{"id":"323899","messageId":"xmqqo9sxfscp.fsf@gitster.mtv.corp.google.com","threadId":"46316","inReplyTo":"b28bc109-b06f-0acf-960b-0b6761b0ee38@email.unc.edu","subject":"Re: bug report: dates on diff","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-07-06T16:22:14Z","receivedAt":"2017-07-06T16:22:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Todd Lewis <utoddl@email.unc.edu> writes:\n\n> [utoddl@tarna gitbug]$ git diff master@{01-01-2012} charter.txt\n> warning: Log for 'master' only goes back to Thu, 6 Jul 2017 08:19:45 -0400.\n\nWhat you observed is how <ref>@{<selector>} syntax is designed to\nwork, and is not limited to \"git diff\".  Any Git command e.g. \"git\nrev-parse master@{01-01-2012}\", would and should behave the same\nway.\n\nThe thing to note is that the syntax does not pay any attention to\nauthor or committer dates recorded in the commit objects.  In fact,\nif you have a ref that points at an object that is not a commit-ish,\nyou can still use the syntax.  If you did this, for example\n\n    $ git config core.logallrefupdates always\n\n    $ one=$(echo one | git hash-object --stdin -w)\n    $ git update-ref refs/my/blob $one\n\n    ... time passes ...\n\n    $ two=$(echo two | git hash-object --stdin -w)\n    $ git update-ref refs/my/blob $two\n\nthen \"git show my/blob@{2.minutes.ago}\" will show the blob object\nyour refs/my/blob ref was pointing at 2 minutes ago.\n\nAnd as you may know, blobs do not record any timestamp.  So how does\nthis work?  \n\nThe reason why this works is because the time in <ref>@{$time}\nsyntax is about asking what was pointed by the <ref> back in $time\nin your repository.  It does not matter what timestamp the object\nthat was pointed by the <ref> has (or does not have).\n\nIf you didn't create this repository back in 2012, then the syntax\n\"master@{01-01-2012}\" that asks \"Back at the beginning of 2012, what\nobject did the master branch point at?\" does not have a sensible\nanswer.  That can be seen in the warning you got from Git.\n\nHope this clarifies.\n"},{"id":"323905","messageId":"53f97d43-6984-6a46-bde2-a8cf64e7bb9e@email.unc.edu","threadId":"46316","inReplyTo":"xmqqo9sxfscp.fsf@gitster.mtv.corp.google.com","subject":"Re: bug report: dates on diff","fromName":"Todd Lewis","fromEmail":"utoddl@email.unc.edu","sentAt":"2017-07-06T17:32:02Z","receivedAt":"2017-07-06T17:32:21Z","isPatch":false,"sender":{"key":"utoddl@email.unc.edu","avatar":null},"body":"\n\nOn 07/06/2017 12:22 PM, Junio C Hamano wrote:\n> If you didn't create this repository back in 2012, then the syntax\n> \"master@{01-01-2012}\" that asks \"Back at the beginning of 2012, what\n> object did the master branch point at?\" does not have a sensible\n> answer.  That can be seen in the warning you got from Git.\n> \n> Hope this clarifies.\n\nThanks; it does explain what I saw, and even makes some sense.\n\nHowever, it does leave me scratching my head about how to accomplish what I set\nout to do, or just how to reference commits by their dates as displayed by git\nlog w/o either changing the system time/date when committing historic data\n(which seems like a total no-no), or making multiple passes over \"get log\" to\ndetermine how to ref. Perhaps there's a way to patch the log to match dates\nrecorded in relevant objects?\n\nTrying not to sound snide, but, what's the point of \"--date=\" on commits if you\ncan't use it later? Granted, things always seem harder until you understand how\nthe work. Thanks again.\n"},{"id":"323908","messageId":"xmqqbmoxfnns.fsf@gitster.mtv.corp.google.com","threadId":"46316","inReplyTo":"53f97d43-6984-6a46-bde2-a8cf64e7bb9e@email.unc.edu","subject":"Re: bug report: dates on diff","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-07-06T18:03:35Z","receivedAt":"2017-07-06T18:03:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Todd Lewis <utoddl@email.unc.edu> writes:\n\n> Trying not to sound snide, but, what's the point of \"--date=\" on commits if you\n> can't use it later? Granted, things always seem harder until you understand how\n> the work. Thanks again.\n\nYou do not sound snide at all, at least to me ;-)\n\nImagine this scenario:\n\n - Contributor A writes a change on 2017-07-01 and send it in to me\n - Contributor B writes a change on 2017-07-03 and send it in to me\n - I apply change from B on 2017-07-04 on 'master'\n - I apply change from A on 2017-07-05 on 'master'\n - You clone the resulting repository from me on 2017-07-06\n\nNow, you have at the tip of 'master' in your repository the commit\nthat records the change by contributor A.\n\nAnd there are three times that are relevant to your tip of 'master'.\n\n - When was the commit that sits at the tip of 'master' made?\n - When was the change recorded in that commit made?\n - When was the commit made at the tip of _your_ 'master'?\n\nand the answers are 2017-07-01, 2017-07-05 and 2017-07-06, respectively.\nThey are called \"committer\", \"author\" and \"reflog\" timestamps.\n\nThe 'master@{<time>}' syntax is about the reflog timestamp.  It\nnever looks at the former two.  In general whenever you see <ref>@{...},\nthat is talking about the information that is stored in \"reflog\",\nthe record of when and in what order the <ref> in _your_ repository\npointed at various objects.\n\nThe \"commit --date=<time>\" is about tweaking the \"author\" timestamp\nthe commit records.  It does not affect the \"committer\" timestamp.\nBy definition (of what \"reflog\" is), it will not affect the reflog\ntimestamp, because the reflog timestamp for a particular commit\nwould be different across repositories.  I had A's commit on _my_\nmaster on 2017-07-05, but the time you had it on _your_ master was\nnot until 2017-07-06.\n\nI think the best way to do this properly would be to extend the\n\"<ref>^{...}\" syntax so that we can say e.g.\n\n    git show \"master^{#author-time > 2017-01-01}\"\n\nto mean \"traverse from the tip of 'master' and find the first commit\nthat satisfies the given expression, \"author-time > 2017-01-01\", i.e.\nhas author timestamp that is later than the specified date.  Which\nwould be in line with the existing\n\n    git show \"master^{/my commit message}\"\n\nthat means \"traverse from the tip of 'master' and find the first\ncommit that has 'my commit message' in the log message\".\n\nNote that \"git log --since=<time> --until=<time> master\" would be\nthe thing that is closest to what you would want that already\nexists, but that limits by the \"committer\" timestamp.  You _could_\nlie about both author and committer timestamp when building the\nbackdated history and use this mechanism, but we have author and\ncommitter timestamps that are distinct for a reason, so it is a\nrather poor workaround.\n\n\n"},{"id":"323909","messageId":"xmqq7ezlfnk7.fsf@gitster.mtv.corp.google.com","threadId":"46316","inReplyTo":"xmqqbmoxfnns.fsf@gitster.mtv.corp.google.com","subject":"Re: bug report: dates on diff","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-07-06T18:05:44Z","receivedAt":"2017-07-06T18:05:52Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Imagine this scenario:\n>\n>  - Contributor A writes a change on 2017-07-01 and send it in to me\n>  - Contributor B writes a change on 2017-07-03 and send it in to me\n>  - I apply change from B on 2017-07-04 on 'master'\n>  - I apply change from A on 2017-07-05 on 'master'\n>  - You clone the resulting repository from me on 2017-07-06\n>\n> Now, you have at the tip of 'master' in your repository the commit\n> that records the change by contributor A.\n>\n> And there are three times that are relevant to your tip of 'master'.\n>\n>  - When was the commit that sits at the tip of 'master' made?\n>  - When was the change recorded in that commit made?\n>  - When was the commit made at the tip of _your_ 'master'?\n>\n> and the answers are 2017-07-01, 2017-07-05 and 2017-07-06, respectively.\n> They are called \"committer\", \"author\" and \"reflog\" timestamps.\n\nOops, obviously the dates have to be 2017-07-05, 2017-07-01 and\n2017-07-06.  I made the commit on the 5th (i.e. \"committer\"\ntimestamp) that records a change written on the 1st (i.e. \"author\"\ntimestamp).\n"}]}