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>
Junio C Hamano committed
May 2, 2011 at 13:39 UTC
003c84f6d2b9e9c4d5bbf5262cae994bac7190cb
5 files changed
+56
-4
Documentation/revisions.txt
+7
@@ -213,6 +213,13 @@ of 'r1' and 'r2' and is defined as
213
It is the set of commits that are reachable from either one of
214
'r1' or 'r2' but not from both.
215
216
+In these two shorthands, you can omit one end and let it default to HEAD.
217
+For example, 'origin..' is a shorthand for 'origin..HEAD' and asks "What
218
+did I do since I forked from the origin branch?" Similarly, '..origin'
219
+is a shorthand for 'HEAD..origin' and asks "What did the origin do since
220
+I forked from them?" Note that '..' would mean 'HEAD..HEAD' which is an
221
+empty range that is both reachable and unreachable from HEAD.
222
+
223
Two other shorthands for naming a set that is formed by a commit
224
and its parent commits exist. The 'r1{caret}@' notation means all
225
parents of 'r1'. 'r1{caret}!' includes commit 'r1' but excludes
builtin/rev-parse.c
+14
-2
@@ -224,6 +224,7 @@ static int try_difference(const char *arg)
224
const char *next;
225
const char *this;
226
int symmetric;
227
+ static const char head_by_default[] = "HEAD";
228
229
if (!(dotdot = strstr(arg, "..")))
230
return 0;
@@ -235,9 +236,20 @@ static int try_difference(const char *arg)
236
next += symmetric;
237
238
if (!*next)
238
- next = "HEAD";
239
+ next = head_by_default;
240
if (dotdot == arg)
240
- this = "HEAD";
241
+ this = head_by_default;
242
+
243
+ if (this == head_by_default && next == head_by_default &&
244
+ !symmetric) {
245
+ /*
246
+ * Just ".."? That is not a range but the
247
+ * pathspec for the parent directory.
248
+ */
249
+ *dotdot = '.';
250
+ return 0;
251
+ }
252
+
253
if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
254
show_rev(NORMAL, end, next);
255
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
revision.c
+14
-2
@@ -1132,15 +1132,27 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
1132
const char *this = arg;
1133
int symmetric = *next == '.';
1134
unsigned int flags_exclude = flags ^ UNINTERESTING;
1135
+ static const char head_by_default[] = "HEAD";
1136
unsigned int a_flags;
1137
1138
*dotdot = 0;
1139
next += symmetric;
1140
1141
if (!*next)
1141
- next = "HEAD";
1142
+ next = head_by_default;
1143
if (dotdot == arg)
1143
- this = "HEAD";
1144
+ this = head_by_default;
1145
+ if (this == head_by_default && next == head_by_default &&
1146
+ !symmetric) {
1147
+ /*
1148
+ * Just ".."? That is not a range but the
1149
+ * pathspec for the parent directory.
1150
+ */
1151
+ if (!cant_be_filename) {
1152
+ *dotdot = '.';
1153
+ return -1;
1154
+ }
1155
+ }
1156
if (!get_sha1(this, from_sha1) &&
1157
!get_sha1(next, sha1)) {
1158
struct commit *a, *b;
t/t1506-rev-parse-diagnosis.sh
+14
@@ -182,4 +182,18 @@ test_expect_success '<commit>:file correctly diagnosed after a pathname' '
182
test_cmp expect actual
183
'
184
185
+test_expect_success 'dotdot is not an empty set' '
186
+ ( H=$(git rev-parse HEAD) && echo $H && echo ^$H ) >expect &&
187
+
188
+ git rev-parse HEAD.. >actual &&
189
+ test_cmp expect actual &&
190
+
191
+ git rev-parse ..HEAD >actual &&
192
+ test_cmp expect actual &&
193
+
194
+ echo .. >expect &&
195
+ git rev-parse .. >actual &&
196
+ test_cmp expect actual
197
+'
198
+
199
test_done
t/t4202-log.sh
+7
@@ -806,4 +806,11 @@ test_expect_success 'log --graph with diff and stats' '
806
test_cmp expect actual.sanitized
807
'
808
809
+test_expect_success 'dotdot is a parent directory' '
810
+ mkdir -p a/b &&
811
+ ( echo sixth && echo fifth ) >expect &&
812
+ ( cd a/b && git log --format=%s .. ) >actual &&
813
+ test_cmp expect actual
814
+'
815
+
816
test_done