Either end of revision range operator can be omitted to default to HEAD, as in "origin.." (what did I do since I forked) or "..origin" (what did they do since I forked). But the current parser interprets ".." as an empty range "HEAD..HEAD", and worse yet, because ".." does exist on the filesystem, we get this annoying output: $ cd Documentation/howto $ git log .. ;# give me recent commits that touch Documentation/ area. fatal: ambiguous argument '..': both revision and filename Use '--' to separate filenames from revisions Surely we could say "git log ../" or even "git log -- .." to disambiguate, but we shouldn't have to. Helped-by: Jeff King <peff@xxxxxxxx> Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx> --- * With docs and tests. In an early version, I forgot to restore the revision string that is temporarily NUL terminated with *dotdot = '.', which resulted in "git log .." from Doc/howto to show not just the log of Doc but show everything. The new test in t4202 tries to catch that rather common mistake as well. Documentation/revisions.txt | 7 +++++++ builtin/rev-parse.c | 16 ++++++++++++++-- revision.c | 16 ++++++++++++++-- t/t1506-rev-parse-diagnosis.sh | 14 ++++++++++++++ t/t4202-log.sh | 7 +++++++ 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index 3d4b79c..fd043f7 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -184,6 +184,13 @@ of `r1` and `r2` and is defined as It is the set of commits that are reachable from either one of `r1` or `r2` but not from both. +In these two shorthands, you can omit one end and let it default to HEAD. +For example, 'origin..' is a shorthand for 'origin..HEAD' and asks "What +did I do since I forked from the origin branch?" Similarly, '..origin' +is a shorthand for 'HEAD..origin' and asks "What did the origin do since +I forked from them?" Note that you cannot omit both ends. '..' is not +an empty range that is both reachable and unreachable from HEAD. + Two other shorthands for naming a set that is formed by a commit and its parent commits exist. The `r1{caret}@` notation means all parents of `r1`. `r1{caret}!` includes commit `r1` but excludes diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index a5a1c86..54ce44b 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -219,6 +219,7 @@ static int try_difference(const char *arg) const char *next; const char *this; int symmetric; + static const char head_by_default[] = "HEAD"; if (!(dotdot = strstr(arg, ".."))) return 0; @@ -230,9 +231,20 @@ static int try_difference(const char *arg) next += symmetric; if (!*next) - next = "HEAD"; + next = head_by_default; if (dotdot == arg) - this = "HEAD"; + this = head_by_default; + + if (this == head_by_default && next == head_by_default && + !symmetric) { + /* + * Just ".."? That is not a range but the + * pathspec for the parent directory. + */ + *dotdot = '.'; + return 0; + } + if (!get_sha1(this, sha1) && !get_sha1(next, end)) { show_rev(NORMAL, end, next); show_rev(symmetric ? NORMAL : REVERSED, sha1, this); diff --git a/revision.c b/revision.c index ded8812..4572aaf 100644 --- a/revision.c +++ b/revision.c @@ -1004,14 +1004,26 @@ int handle_revision_arg(const char *arg, struct rev_info *revs, const char *this = arg; int symmetric = *next == '.'; unsigned int flags_exclude = flags ^ UNINTERESTING; + static const char head_by_default[] = "HEAD"; *dotdot = 0; next += symmetric; if (!*next) - next = "HEAD"; + next = head_by_default; if (dotdot == arg) - this = "HEAD"; + this = head_by_default; + if (this == head_by_default && next == head_by_default && + !symmetric) { + /* + * Just ".."? That is not a range but the + * pathspec for the parent directory. + */ + if (!cant_be_filename) { + *dotdot = '.'; + return -1; + } + } if (!get_sha1(this, from_sha1) && !get_sha1(next, sha1)) { struct commit *a, *b; diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh index 0eeeb0e..4485d0a 100755 --- a/t/t1506-rev-parse-diagnosis.sh +++ b/t/t1506-rev-parse-diagnosis.sh @@ -75,4 +75,18 @@ test_expect_success 'invalid @{n} reference' ' grep "fatal: Log for [^ ]* only has [0-9][0-9]* entries." error ' +test_expect_success 'dotdot is not an empty set' ' + ( H=$(git rev-parse HEAD) && echo $H ; echo ^$H ) >expect && + + git rev-parse HEAD.. >actual && + test_cmp expect actual && + + git rev-parse ..HEAD >actual && + test_cmp expect actual && + + echo .. >expect && + git rev-parse .. >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 2043bb8..b89f9af 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -463,4 +463,11 @@ test_expect_success 'show added path under "--follow -M"' ' ) ' +test_expect_success 'dotdot is a parent directory' ' + mkdir -p a/b && + ( echo sixth && echo fifth ) >expect && + ( cd a/b && git log --format=%s .. ) >actual && + test_cmp expect actual +' + test_done -- 1.7.5.253.g2243e -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html