specifying ranges: we did not mean to make ".." an empty set
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@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
c142616fb2
commit
003c84f6d2
@ -213,6 +213,13 @@ of 'r1' and 'r2' and is defined as
|
|||||||
It is the set of commits that are reachable from either one of
|
It is the set of commits that are reachable from either one of
|
||||||
'r1' or 'r2' but not from both.
|
'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 '..' would mean 'HEAD..HEAD' which is an
|
||||||
|
empty range that is both reachable and unreachable from HEAD.
|
||||||
|
|
||||||
Two other shorthands for naming a set that is formed by a commit
|
Two other shorthands for naming a set that is formed by a commit
|
||||||
and its parent commits exist. The 'r1{caret}@' notation means all
|
and its parent commits exist. The 'r1{caret}@' notation means all
|
||||||
parents of 'r1'. 'r1{caret}!' includes commit 'r1' but excludes
|
parents of 'r1'. 'r1{caret}!' includes commit 'r1' but excludes
|
||||||
|
@ -224,6 +224,7 @@ static int try_difference(const char *arg)
|
|||||||
const char *next;
|
const char *next;
|
||||||
const char *this;
|
const char *this;
|
||||||
int symmetric;
|
int symmetric;
|
||||||
|
static const char head_by_default[] = "HEAD";
|
||||||
|
|
||||||
if (!(dotdot = strstr(arg, "..")))
|
if (!(dotdot = strstr(arg, "..")))
|
||||||
return 0;
|
return 0;
|
||||||
@ -235,9 +236,20 @@ static int try_difference(const char *arg)
|
|||||||
next += symmetric;
|
next += symmetric;
|
||||||
|
|
||||||
if (!*next)
|
if (!*next)
|
||||||
next = "HEAD";
|
next = head_by_default;
|
||||||
if (dotdot == arg)
|
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)) {
|
if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
|
||||||
show_rev(NORMAL, end, next);
|
show_rev(NORMAL, end, next);
|
||||||
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
|
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
|
||||||
|
16
revision.c
16
revision.c
@ -1132,15 +1132,27 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
|
|||||||
const char *this = arg;
|
const char *this = arg;
|
||||||
int symmetric = *next == '.';
|
int symmetric = *next == '.';
|
||||||
unsigned int flags_exclude = flags ^ UNINTERESTING;
|
unsigned int flags_exclude = flags ^ UNINTERESTING;
|
||||||
|
static const char head_by_default[] = "HEAD";
|
||||||
unsigned int a_flags;
|
unsigned int a_flags;
|
||||||
|
|
||||||
*dotdot = 0;
|
*dotdot = 0;
|
||||||
next += symmetric;
|
next += symmetric;
|
||||||
|
|
||||||
if (!*next)
|
if (!*next)
|
||||||
next = "HEAD";
|
next = head_by_default;
|
||||||
if (dotdot == arg)
|
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) &&
|
if (!get_sha1(this, from_sha1) &&
|
||||||
!get_sha1(next, sha1)) {
|
!get_sha1(next, sha1)) {
|
||||||
struct commit *a, *b;
|
struct commit *a, *b;
|
||||||
|
@ -182,4 +182,18 @@ test_expect_success '<commit>:file correctly diagnosed after a pathname' '
|
|||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
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
|
test_done
|
||||||
|
@ -806,4 +806,11 @@ test_expect_success 'log --graph with diff and stats' '
|
|||||||
test_cmp expect actual.sanitized
|
test_cmp expect actual.sanitized
|
||||||
'
|
'
|
||||||
|
|
||||||
|
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
|
test_done
|
||||||
|
Loading…
Reference in New Issue
Block a user