{"thread":{"id":"51607","subject":"[PATCH] blame: document actual range specifier behavior","startedAt":"2019-08-08T01:19:38Z","lastAt":"2019-08-09T16:58:25Z","messageCount":3,"participants":["Daniel Koning","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"380106","messageId":"m2ftmcijgk.fsf@danielkoning.com","threadId":"51607","inReplyTo":null,"subject":"[PATCH] blame: document actual range specifier behavior","fromName":"Daniel Koning","fromEmail":"dk@danielkoning.com","sentAt":"2019-08-08T00:10:20Z","receivedAt":"2019-08-08T01:19:38Z","isPatch":true,"sender":{"key":"dk@danielkoning.com","avatar":null},"body":"The git-blame(1) man page says that the .. range specifier can be used\nto exclude changes \"older than\" a certain revision. It goes on to say\nthat it collapses all lines \"not changed since the range boundary\" into\nthe boundary revision. This is the same thing --since=<rev-date> would\ndo, and the man page even uses .. and --since in parallel as if to imply\nthat they're alternative means of achieving the same output.\n\nIn fact, this isn't true! On the git-rev-list(1) and gitrevisions(7) man\npages, it's explained that the .. specifier excludes all ancestors of\nthe commit, not all commits on an earlier date. 'blame' is not an\nexception to this behavior; it uses the same functions as other commands\nto parse a specifier and build a revision set.\n\nIf you execute:\n\n----\n#!/bin/sh\n\nmkdir blame-test\npushd blame-test\n\ngit init\necho \"line added at root\" > foo\necho \"another line added at root\" >> foo\ngit add foo\ngit commit -am \"#1 chronologically\"\n\ngit checkout -b side\nsed '2i\\\n    line added only on side branch\n    ' foo > bar\nmv bar foo\ngit commit -am \"#2 chronologically\"\n\ngit checkout master\necho \"line added only on master branch\" >> foo\ngit commit -am \"#3 chronologically\"\ngit tag boundary\n\ngit merge side -m \"#4 chronologically\"\n\ngit blame boundary.. foo\n\npopd blame-test\n----\n\nthen you'll see that 'blame' treats the range specifier as 'rev-list'\nwould: the second line is attributed to a commit which occured\nchronologically before `boundary`.\n\n(I guess a case could be made for an off-kilter interpretation of the\nphrasing, under which \"since the range boundary\" includes any commits\nnot yet known to that boundary. But that would contradict the use of\n\"since\" as the name of the other limiting option, which *does* perform\nan absolute time cutoff.)\n\nThere is at least one porcelain in fairly wide use which takes this\npassage of the manual at its word, so I'm not the only one who finds it\nconfusing. I think the phrasing in the following patch is both clearer\nand more accurate.\n\nSigned-off-by: Daniel Koning <dk@danielkoning.com>\n---\n Documentation/git-blame.txt | 32 ++++++++++++++++++++------------\n 1 file changed, 20 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt\nindex 16323eb80e..91f3184e56 100644\n--- a/Documentation/git-blame.txt\n+++ b/Documentation/git-blame.txt\n@@ -152,18 +152,26 @@ Also you can use a regular expression to specify the line range:\n\n which limits the annotation to the body of the `hello` subroutine.\n\n-When you are not interested in changes older than version\n-v2.6.18, or changes older than 3 weeks, you can use revision\n-range specifiers  similar to 'git rev-list':\n-\n-\tgit blame v2.6.18.. -- foo\n-\tgit blame --since=3.weeks -- foo\n-\n-When revision range specifiers are used to limit the annotation,\n-lines that have not changed since the range boundary (either the\n-commit v2.6.18 or the most recent commit that is more than 3\n-weeks old in the above example) are blamed for that range\n-boundary commit.\n+When you are only interested in recent changes, you can use revision\n+range specifiers and limiting options, just as with 'git rev-list'.\n+\n+You can limit the annotation to commits from the past 3 weeks:\n+\n+  git blame --since=3.weeks -- foo\n+\n+The oldest commit in that span of time will be given the blame for any\n+lines that have not changed since.\n+\n+Or you can limit the annotation to commits that are not ancestors of\n+v2.6.18:\n+\n+  git blame v2.6.18.. -- foo\n+\n+Unlike the --since option, the two-dot range specifier does not perform\n+a date-based cutoff. If changes from branch `fix` were merged in after\n+v2.6.18, the commits on `fix` which introduced those changes will appear\n+in the output of 'git blame', even if those commits took place at an\n+earlier time than v2.6.18.\n\n A particularly useful way is to see if an added file has lines\n created by copy-and-paste from existing files.  Sometimes this\n--\n2.20.1\n\n"},{"id":"380148","messageId":"xmqqsgqbfucj.fsf@gitster-ct.c.googlers.com","threadId":"51607","inReplyTo":"m2ftmcijgk.fsf@danielkoning.com","subject":"Re: [PATCH] blame: document actual range specifier behavior","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-08-08T17:19:24Z","receivedAt":"2019-08-08T17:19:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Koning <dk@danielkoning.com> writes:\n\n> The git-blame(1) man page says that the .. range specifier can be used\n> to exclude changes \"older than\" a certain revision.\n\nThanks for spoting a loose-and-colloquial use of \"older than\" in the\ndoc.  As you suspect, the document wanted the phrase to be understood\nas \"reachable from\" (a.k.a \"ancestor of\").  \n\nBefore reading your proposed updated text, I feared that an attempt\nto be techinically more precise by rewriting description that uses\nmore colloquial \"older than\" may make the result cumbersome to read,\nand as I suspected the result did become so, but it does not look\ntoo bad, either, but the explanation of how boundary commits are\nshown is completely lost, which is not quite satisfactory.\n\nI personally find \"unlike ... does not perform date-based cutoff\" a\nbit too redundant---as you know, it is known that everywhere in Git,\ndots notation is about limiting by revision range a.k.a ancestry\nrelationships, and the reader can interpret \"older than\" as\n\"reachable from\", once the context is clear enough.  If anything,\nperhaps such a description should go to \"git help revisions\", as it\nis not just \"blame\" but \"log\". \"The dots notation is not about\ndate-based cutoff, unlike the --since/--until options\" is shared by\nall history traversal tools.\n\n>  which limits the annotation to the body of the `hello` subroutine.\n>\n> -When you are not interested in changes older than version\n> -v2.6.18, or changes older than 3 weeks, you can use revision\n> -range specifiers  similar to 'git rev-list':\n> -\n> -\tgit blame v2.6.18.. -- foo\n> -\tgit blame --since=3.weeks -- foo\n> -\n> -When revision range specifiers are used to limit the annotation,\n> -lines that have not changed since the range boundary (either the\n> -commit v2.6.18 or the most recent commit that is more than 3\n> -weeks old in the above example) are blamed for that range\n> -boundary commit.\n> +When you are only interested in recent changes, you can use revision\n> +range specifiers and limiting options, just as with 'git rev-list'.\n> +\n> +You can limit the annotation to commits from the past 3 weeks:\n> +\n> +  git blame --since=3.weeks -- foo\n> +\n> +The oldest commit in that span of time will be given the blame for any\n> +lines that have not changed since.\n> +\n> +Or you can limit the annotation to commits that are not ancestors of\n> +v2.6.18:\n> +\n> +  git blame v2.6.18.. -- foo\n> +\n> +Unlike the --since option, the two-dot range specifier does not perform\n> +a date-based cutoff. If changes from branch `fix` were merged in after\n> +v2.6.18, the commits on `fix` which introduced those changes will appear\n> +in the output of 'git blame', even if those commits took place at an\n> +earlier time than v2.6.18.\n>\n>  A particularly useful way is to see if an added file has lines\n>  created by copy-and-paste from existing files.  Sometimes this\n> --\n> 2.20.1\n"},{"id":"380224","messageId":"xmqqblwye0nn.fsf@gitster-ct.c.googlers.com","threadId":"51607","inReplyTo":"xmqqsgqbfucj.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH] blame: document actual range specifier behavior","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-08-09T16:58:20Z","receivedAt":"2019-08-09T16:58:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> ...  If anything,\n> perhaps such a description should go to \"git help revisions\", as it\n> is not just \"blame\" but \"log\". \"The dots notation is not about\n> date-based cutoff, unlike the --since/--until options\" is shared by\n> all history traversal tools.\n\nBy this, I do not necessarily mean \"hence such a piece of info\nshould not be added to the documentation of blame\".  Rather, an\nexplanation like \"'^A' limits an operation to commits that are\ntopologically newer than A, while '--since=A' limits to commits that\nare chronologically newer than A\" is shared among \"log\", \"blame\" and\nfriends, and would be better to be clarified in documentation for\nall of them.  Especially ...\n\n>> +  git blame v2.6.18.. -- foo\n>> +\n>> +... If changes from branch `fix` were merged in after\n>> +v2.6.18, the commits on `fix` which introduced those changes will appear\n>> +in the output of 'git blame', even if those commits took place at an\n>> +earlier time than v2.6.18.\n\n... is a brilliant way to illustrate how \"A.., i.e. topologically\nnewer than A\" is different from \"--since=A, i.e. chronologically\nnewer than A\", whose understanding would help readers to understand\nnot just \"blame\" but \"log\".\n\nThanks.\n\n"}]}