{"thread":{"id":"30804","subject":"How do I specify a revision for \"git blame\" by date?","startedAt":"2012-06-14T10:05:56Z","lastAt":"2012-06-16T04:13:03Z","messageCount":9,"participants":["perryh@pluto.rain.com","Thomas Rast","Andreas Schwab","Junio C Hamano","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"193643","messageId":"877gva1a4b.fsf@thomas.inf.ethz.ch","threadId":"30804","inReplyTo":"4fda029d.g99uVull9jgguc/Y%perryh@pluto.rain.com","subject":"Re: How do I specify a revision for \"git blame\" by date?","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2012-06-14T10:05:56Z","receivedAt":"2012-06-14T10:05:56Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"perryh@pluto.rain.com writes:\n\n> How do I get \"git blame\" to operate \"as of\" a particular date in\n> the past, without having to manually look up the corresponding\n> SHA1 using \"git rev-list\"?  For example, I can get a report as of\n> 2011-12-29 by doing something like:\n>\n>   $ git rev-list --all --date-order --format=\"%h %ai\" .\n>   ...\n>   7c69106 2012-01-03 ...\n>   b4227af 2011-12-27 ...\n>   ...\n>\n>   $ git blame <file> b4227af\n>\n> but I want to have git look up the last revision prior to the given\n> date, by doing something like\n>\n>   $ git blame <file> @{2011-12-29}\n\nYou are looking at two different dates:\n\na) The dates stored within the commit object:\n\n   - committer date, similarly shown by %ci: when the commit was created.\n   - author date, shown by %ai: when \"this\" commit was \"first created\".\n\n   These are properties of the commits, and thus part of the project\n   history.  Anyone who clones the project sees the same dates.\n\nb) The dates in the reflog, tracking the movement of *your local* refs\n   (like the name implies).  The HEAD reflog tracks what *you* had\n   \"currently checked out\" at a given time.\n\nAn automated search in (b) is possible with the @{} syntax, but note\nthat it tracks the *branch state*.  It says nothing about how \"current\"\na certain resulting commit was.  For example, if you say\n\n  git checkout v1.6.0\n  sleep 2\n  git checkout -\n  git show '@{1 second ago}'\n\nyou will see the commit for v1.6.0 from back in 2008.\n\nAn automated search in (a) is hard, mostly because in nonlinear history\nthere is not usually a single (and well-defined) commit that could be\nreturned.  Git could attempt to search all of your branches, like you\nhave done above, but which one among all commits from that date should\nit pick?  Furthermore, the result set to pick from will change if you\nfetch more history into your repo.\n\nIt's even worse with the author (as opposed to committer) dates: those\nare not even remotely close to monotonic in most repos, because they are\nkept across rewriting.  (The committer dates would be monotonic if\neveryone kept their clocks in sync and avoided filter-branch tricks.)\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"193644","messageId":"m2sjdynqlf.fsf@igel.home","threadId":"30804","inReplyTo":"4fda029d.g99uVull9jgguc/Y%perryh@pluto.rain.com","subject":"Re: How do I specify a revision for \"git blame\" by date?","fromName":"Andreas Schwab","fromEmail":"schwab@linux-m68k.org","sentAt":"2012-06-14T10:19:08Z","receivedAt":"2012-06-14T10:19:08Z","isPatch":false,"sender":{"key":"schwab@linux-m68k.org","avatar":"https://avatars.githubusercontent.com/u/2175493?v=4"},"body":"perryh@pluto.rain.com writes:\n\n> How do I get \"git blame\" to operate \"as of\" a particular date in\n> the past, without having to manually look up the corresponding\n> SHA1 using \"git rev-list\"?  For example, I can get a report as of\n> 2011-12-29 by doing something like:\n>\n>   $ git rev-list --all --date-order --format=\"%h %ai\" .\n>   ...\n>   7c69106 2012-01-03 ...\n>   b4227af 2011-12-27 ...\n>   ...\n>\n>   $ git blame <file> b4227af\n\nYou can use any rev-list option, so --until=2011-12-27 should work.\n\nAndreas.\n\n-- \nAndreas Schwab, schwab@linux-m68k.org\nGPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5\n\"And now for something completely different.\"\n"},{"id":"193632","messageId":"4fda029d.g99uVull9jgguc/Y%perryh@pluto.rain.com","threadId":"30804","inReplyTo":null,"subject":"How do I specify a revision for \"git blame\" by date?","fromName":"","fromEmail":"perryh@pluto.rain.com","sentAt":"2012-06-14T15:26:21Z","receivedAt":"2012-06-14T15:26:21Z","isPatch":false,"sender":{"key":"perryh@pluto.rain.com","avatar":null},"body":"How do I get \"git blame\" to operate \"as of\" a particular date in\nthe past, without having to manually look up the corresponding\nSHA1 using \"git rev-list\"?  For example, I can get a report as of\n2011-12-29 by doing something like:\n\n  $ git rev-list --all --date-order --format=\"%h %ai\" .\n  ...\n  7c69106 2012-01-03 ...\n  b4227af 2011-12-27 ...\n  ...\n\n  $ git blame <file> b4227af\n\nbut I want to have git look up the last revision prior to the given\ndate, by doing something like\n\n  $ git blame <file> @{2011-12-29}\n\nThis does not work as written:  it ignores the date parameter with\na warning:\n\n  warning: Log for '' only goes back to Thu, 10 May 2012 08:14:16 -0700.\n\nIf I use HEAD@ instead of just @ I get the same message with 'HEAD'\nin place of '', and everything else I've tried gives a \"fatal: bad\nrevision\" message.\n\nClearly, as shown by git rev-list, the log for the _repository_\ngoes back farther than May 10, so this is a problem of finding the\ncorrect syntax rather than of wanting to do something \"impossible\".\nWhat do I need to put in front of the @ to cause the entire log to\nbe examined?\n"},{"id":"193664","messageId":"7vtxyderli.fsf@alter.siamese.dyndns.org","threadId":"30804","inReplyTo":"m2sjdynqlf.fsf@igel.home","subject":"Re: How do I specify a revision for \"git blame\" by date?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-14T17:22:17Z","receivedAt":"2012-06-14T17:22:17Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Schwab <schwab@linux-m68k.org> writes:\n\n> perryh@pluto.rain.com writes:\n>\n>> How do I get \"git blame\" to operate \"as of\" a particular date in\n>> the past, without having to manually look up the corresponding\n>> SHA1 using \"git rev-list\"?  For example, I can get a report as of\n>> 2011-12-29 by doing something like:\n>>\n>>   $ git rev-list --all --date-order --format=\"%h %ai\" .\n>>   ...\n>>   7c69106 2012-01-03 ...\n>>   b4227af 2011-12-27 ...\n>>   ...\n>>\n>>   $ git blame <file> b4227af\n>\n> You can use any rev-list option, so --until=2011-12-27 should work.\n\nNews to me.\n"},{"id":"193683","messageId":"4fdb326f.WB/xRjZx4pXtMhhZ%perryh@pluto.rain.com","threadId":"30804","inReplyTo":"877gva1a4b.fsf@thomas.inf.ethz.ch","subject":"Re: How do I specify a revision for \"git blame\" by date?","fromName":"","fromEmail":"perryh@pluto.rain.com","sentAt":"2012-06-15T13:02:39Z","receivedAt":"2012-06-15T13:02:39Z","isPatch":false,"sender":{"key":"perryh@pluto.rain.com","avatar":null},"body":"Thomas Rast <trast@student.ethz.ch> wrote:\n\n> perryh@pluto.rain.com writes:\n>\n> > How do I get \"git blame\" to operate \"as of\" a particular date in\n> > the past, without having to manually look up the corresponding\n> > SHA1 using \"git rev-list\"?  For example, I can get a report as\n> > of 2011-12-29 by doing something like:\n> >\n> >   $ git rev-list --all --date-order --format=\"%h %ai\" .\n> >   ...\n> >   7c69106 2012-01-03 ...\n> >   b4227af 2011-12-27 ...\n> >   ...\n> >\n> >   $ git blame <file> b4227af\n> >\n> > but I want to have git look up the last revision prior to the\n> > given date, by doing something like\n> >\n> >   $ git blame <file> @{2011-12-29}\n>\n> You are looking at two different dates:\n>\n> a) The dates stored within the commit object:\n>\n>    - committer date, similarly shown by %ci: when the commit\n>      was created.\n>    - author date, shown by %ai: when \"this\" commit was \"first\n>      created\".\n>\n>    These are properties of the commits, and thus part of the project\n>    history.  Anyone who clones the project sees the same dates.\n>\n> b) The dates in the reflog, tracking the movement of *your local*\n>    refs (like the name implies).  The HEAD reflog tracks what *you*\n>    had \"currently checked out\" at a given time.\n>\n> An automated search in (b) is possible with the @{} syntax, but\n> note that it tracks the *branch state*.  It says nothing about how\n> \"current\" a certain resulting commit was.  For example, if you say\n>\n>   git checkout v1.6.0\n>   sleep 2\n>   git checkout -\n>   git show '@{1 second ago}'\n>\n> you will see the commit for v1.6.0 from back in 2008.\n>\n> An automated search in (a) is hard, mostly because in nonlinear\n> history there is not usually a single (and well-defined) commit\n> that could be returned.\n\nGiven that we are discussing \"git blame\", which reports on the\nhistory of a file (specifically the commit in which each line\noriginated), I think (a) must logically be included in the search\n-- especially if (as in the example) the date specified is earlier\nthan any time in (b).  Perhaps such a request needs to use some\nother syntax rather than @{}, but surely the capability ought to\nbe provided somehow.\n\n> Git could attempt to search all of your branches, like you have\n> done above ...\n\nActually, I am not at all sure that one would want --all in the\ngeneral case; it works well in my particular case because all\nbranches in this repository have been merged back to master.\n\nIntuitively, I suspect that the default search set should be all\ncommits reachable from HEAD.  (BTW I may not have the terminology\nexactly right; while I have been working with other CM systems\nfor a couple of decades, I am quite new to git and there is much\nabout it that I do not yet understand.)\n\n> but which one among all commits from that date should it pick?\n\nThe latest one that is not later than the specified date (and time\n-- a timestamp within {} can provide more granularity than just\nthe day; in the example provided there were in fact no commits on\n2011-12-29 so no ambiguity would arise from using the date alone.)\n\n> Furthermore, the result set to pick from will change if you\n> fetch more history into your repo.\n\nUsing the \"commits reachable from HEAD\" strategy above, I think\nnot, unless I also merge from some of that additional history.\n\n> It's even worse with the author (as opposed to committer) dates:\n> those are not even remotely close to monotonic in most repos,\n> because they are kept across rewriting.  (The committer dates\n> would be monotonic if everyone kept their clocks in sync and\n> avoided filter-branch tricks.)\n\nSince it is the file's included commits that \"git blame\" reports on,\nI doubt it would be all that useful to deal in anything other than\ncommit dates.  (I seem to have copy-pasted the wrong format in the\nrev-list part of the example -- it should be \"%h %ci\".)\n"},{"id":"193682","messageId":"4fdb32a0.EloBUowXA1Rtd36K%perryh@pluto.rain.com","threadId":"30804","inReplyTo":"m2sjdynqlf.fsf@igel.home","subject":"Re: How do I specify a revision for \"git blame\" by date?","fromName":"","fromEmail":"perryh@pluto.rain.com","sentAt":"2012-06-15T13:03:28Z","receivedAt":"2012-06-15T13:03:28Z","isPatch":false,"sender":{"key":"perryh@pluto.rain.com","avatar":null},"body":"Andreas Schwab <schwab@linux-m68k.org> wrote:\n\n> perryh@pluto.rain.com writes:\n> > How do I get \"git blame\" to operate \"as of\" a particular date in\n> > the past, without having to manually look up the corresponding\n> > SHA1 using \"git rev-list\"?\n>\n> You can use any rev-list option, so --until=2011-12-27 should work.\n\nThat gets rid of the warning message, but it doesn't produce the\ndesired results.  Whether specified as\n\n  $ git blame <file> --until=2011-12-27\n\nor\n\n  $ git blame --until=2011-12-27 <file>\n\nthe report still includes commits that are much more recent than\n2011-12-27, and it omits material that was deleted since then --\nmaterial which _is_ included when specifying the SHA1 of the commit\nwhich the --until should have identified.  IOW, the --until seems\nto be silently ignored.\n\nI guess this is a bug if rev-list options are supposed to work in\n\"git blame\".  If they are _not_ supposed to work there, I would\nclaim that the failure to generate an error or warning message (when\nI've asked for something that's not intended to work) is a bug.\n"},{"id":"193698","messageId":"20120615150107.GA4572@sigill.intra.peff.net","threadId":"30804","inReplyTo":"4fdb326f.WB/xRjZx4pXtMhhZ%perryh@pluto.rain.com","subject":"Re: How do I specify a revision for \"git blame\" by date?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-06-15T15:01:08Z","receivedAt":"2012-06-15T15:01:08Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jun 15, 2012 at 06:02:39AM -0700, perryh@pluto.rain.com wrote:\n\n> > You are looking at two different dates:\n> >\n> > a) The dates stored within the commit object:\n> >\n> >    - committer date, similarly shown by %ci: when the commit\n> >      was created.\n> >    - author date, shown by %ai: when \"this\" commit was \"first\n> >      created\".\n> >\n> >    These are properties of the commits, and thus part of the project\n> >    history.  Anyone who clones the project sees the same dates.\n> >\n> > b) The dates in the reflog, tracking the movement of *your local*\n> >    refs (like the name implies).  The HEAD reflog tracks what *you*\n> >    had \"currently checked out\" at a given time.\n> >\n> > An automated search in (b) is possible with the @{} syntax, but\n> > note that it tracks the *branch state*.  It says nothing about how\n> > \"current\" a certain resulting commit was.  For example, if you say\n> >\n> >   git checkout v1.6.0\n> >   sleep 2\n> >   git checkout -\n> >   git show '@{1 second ago}'\n> >\n> > you will see the commit for v1.6.0 from back in 2008.\n> >\n> > An automated search in (a) is hard, mostly because in nonlinear\n> > history there is not usually a single (and well-defined) commit\n> > that could be returned.\n> \n> Given that we are discussing \"git blame\", which reports on the\n> history of a file (specifically the commit in which each line\n> originated), I think (a) must logically be included in the search\n> -- especially if (as in the example) the date specified is earlier\n> than any time in (b).  Perhaps such a request needs to use some\n> other syntax rather than @{}, but surely the capability ought to\n> be provided somehow.\n\nIt would have to use a different syntax, as reflog times (selected by\n@{}) and commit dates (usually selected via --since and --until) are\nmeasuring fundamentally different things, and have no meaningful\nrelation to each other.\n\nBut that still doesn't address the issue that (a) is not well-defined.\nImagine I have this history:\n\n\n  A--B--C---G--H\n   \\       /\n    D--E--F\n\nthat is, two lines of development splitting at A and merging at H. And\nimagine the commit timestamps are (let's just refer to them as integers\nfor the sake of simplicity, but they are representing days or seconds or\nwhatever):\n\n  A(1)--B(2)--C(3)--G(7)--H(8)\n   \\               /\n    D(2)--E(4)--F(6)\n\nWhat does it mean to ask for the commit at time=5? If you were to choose\nthe commit with the highest timestamp <= 5, you would pick E. But there\nare two independent, simultaneous lines of development, and at time=5 on\nthe top branch, the most current commit was C.\n\nSo the question doesn't make sense. There was no one commit at time=5;\nthere were multiple (as many as you have simultaneous branches). You can\npick a winner out of them, but there are multiple ways to do it. For\nexample, you might want to say \"of all lines of development, the one\nthat had most recently committed as of time=5\" (and of course you can\nstill have a tie there). Or you could say \"along the first-parent\nancestry, the commit that was most recent as of time=5\". I am sure one\ncould come up with others, as well.\n\nGit-blame expects you to give it a well-defined point (as it must, since\nit is a backwards walk down history showing what led to a particular set\nof content; it wouldn't make sense to feed it multiple starting points).\nYou could do so by asking rev-list to walk the graph according to your\nrequirements and feeding the result to blame, like:\n\n  # most recent on any line of development that is merged to HEAD\n  git blame `git rev-list -1 --until=5 HEAD`\n\n  # most recent on any line of development in the whole repo\n  git blame `git rev-list -1 --until=5 --all`\n\n  # most recent version on the first-parent; if you follow a\n  # topic-branch workflow and always merge up into \"master\", then this\n  # will blame what was on master at time=5\n  git blame `git rev-list -1 --until=5 --first-parent HEAD`\n\n-Peff\n"},{"id":"193704","messageId":"7vsjdwbmh6.fsf@alter.siamese.dyndns.org","threadId":"30804","inReplyTo":"20120615150107.GA4572@sigill.intra.peff.net","subject":"Re: How do I specify a revision for \"git blame\" by date?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-15T15:53:25Z","receivedAt":"2012-06-15T15:53:25Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> But that still doesn't address the issue that (a) is not well-defined.\n> Imagine I have this history:\n>\n>   A--B--C---G--H\n>    \\       /\n>     D--E--F\n>\n> that is, two lines of development splitting at A and merging at H. And\n> imagine the commit timestamps are (let's just refer to them as integers\n> for the sake of simplicity, but they are representing days or seconds or\n> whatever):\n>\n>   A(1)--B(2)--C(3)--G(7)--H(8)\n>    \\               /\n>     D(2)--E(4)--F(6)\n>\n> What does it mean to ask for the commit at time=5?\n> ...\n> Git-blame expects you to give it a well-defined point (as it must, since\n> it is a backwards walk down history showing what led to a particular set\n> of content; it wouldn't make sense to feed it multiple starting points).\n> You could do so by asking rev-list to walk the graph according to your\n> requirements and feeding the result to blame, like:\n>\n>   # most recent on any line of development that is merged to HEAD\n>   git blame `git rev-list -1 --until=5 HEAD`\n>\n>   # most recent on any line of development in the whole repo\n>   git blame `git rev-list -1 --until=5 --all`\n>\n>   # most recent version on the first-parent; if you follow a\n>   # topic-branch workflow and always merge up into \"master\", then this\n>   # will blame what was on master at time=5\n>   git blame `git rev-list -1 --until=5 --first-parent HEAD`\n\nVery well explained.  Thanks.\n\nThe short answer to the question on \"Subject:\" line is \"You don't\".\n"},{"id":"193753","messageId":"4fdc6a3f.nzZc1m4KnwQe3s+K%perryh@pluto.rain.com","threadId":"30804","inReplyTo":"7vsjdwbmh6.fsf@alter.siamese.dyndns.org","subject":"Re: How do I specify a revision for \"git blame\" by date?","fromName":"","fromEmail":"perryh@pluto.rain.com","sentAt":"2012-06-16T04:13:03Z","receivedAt":"2012-06-16T04:13:03Z","isPatch":false,"sender":{"key":"perryh@pluto.rain.com","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> Jeff King <peff@peff.net> writes:\n> > But that still doesn't address the issue that (a) is not\n> > well-defined.  Imagine I have this history:\n> >\n> >   A--B--C---G--H\n> >    \\       /\n> >     D--E--F\n> >\n> > that is, two lines of development splitting at A and merging\n> > at H. And imagine the commit timestamps are (let's just refer\n> > to them as integers for the sake of simplicity, but they are\n> > representing days or seconds or whatever):\n> >\n> >   A(1)--B(2)--C(3)--G(7)--H(8)\n> >    \\               /\n> >     D(2)--E(4)--F(6)\n> >\n> > What does it mean to ask for the commit at time=5?\n> > ...\n> > Git-blame expects you to give it a well-defined point ...\n> > You could do so by asking rev-list to walk the graph according\n> > to your requirements and feeding the result to blame, like:\n> >\n> >   # most recent on any line of development that is merged to HEAD\n> >   git blame `git rev-list -1 --until=5 HEAD`\n> >\n> >   # most recent on any line of development in the whole repo\n> >   git blame `git rev-list -1 --until=5 --all`\n> >\n> >   # most recent version on the first-parent; if you follow a\n> >   # topic-branch workflow and always merge up into \"master\",\n> >   # then this will blame what was on master at time=5\n> >   git blame `git rev-list -1 --until=5 --first-parent HEAD`\n>\n> Very well explained.  Thanks.\n\n+1\n\n> The short answer to the question on \"Subject:\" line is \"You don't\".\n\nThe slightly longer, but perhaps more practically useful, answer is\n\"You use 'git rev-list' to look up the correct commit, and shell\n'command substitution' to pass the result to 'git blame', as Jeff\nhas illustrated.\"  That solution sure beats displaying the entire\nrevision list, and then manually selecting the desired commit from\nit.\n"}]}