get_sha1: support $commit^{/regex} syntax
This works like ":/regex" syntax that finds a recently created commit starting from all refs, but limits the discovery to those reachable from the named commit. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Dec 13, 2010 at 10:01 UTC
32574b68c57f3b34e58216a4c9c6d570d11ec47b
3 files changed
+105
-11
Documentation/revisions.txt
+6
@@ -106,6 +106,12 @@ the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
106
and dereference the tag recursively until a non-tag object is
107
found.
108
109
+* A suffix '{caret}' to a revision parameter followed by a brace
110
+ pair that contains a text led by a slash (e.g. `HEAD^{/fix nasty bug}`):
111
+ this is the same as `:/fix nasty bug` syntax below except that
112
+ it returns the youngest matching commit which is reachable from
113
+ the ref before '{caret}'.
114
+
115
* A colon, followed by a slash, followed by a text (e.g. `:/fix nasty bug`): this names
116
a commit whose commit message matches the specified regular expression.
117
This name returns the youngest matching commit which is
sha1_name.c
+26
-11
@@ -7,6 +7,8 @@
7
#include "refs.h"
8
#include "remote.h"
9
10
+static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
11
+
12
static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
13
{
14
struct alternate_object_database *alt;
@@ -562,6 +564,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
564
expected_type = OBJ_BLOB;
565
else if (sp[0] == '}')
566
expected_type = OBJ_NONE;
567
+ else if (sp[0] == '/')
568
+ expected_type = OBJ_COMMIT;
569
else
570
return -1;
571
@@ -576,19 +580,30 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
580
if (!o || (!o->parsed && !parse_object(o->sha1)))
581
return -1;
582
hashcpy(sha1, o->sha1);
583
+ return 0;
584
}
580
- else {
581
- /*
582
- * At this point, the syntax look correct, so
583
- * if we do not get the needed object, we should
584
- * barf.
585
- */
586
- o = peel_to_type(name, len, o, expected_type);
587
- if (o) {
588
- hashcpy(sha1, o->sha1);
589
- return 0;
590
- }
585
+
586
+ /*
587
+ * At this point, the syntax look correct, so
588
+ * if we do not get the needed object, we should
589
+ * barf.
590
+ */
591
+ o = peel_to_type(name, len, o, expected_type);
592
+ if (!o)
593
return -1;
594
+
595
+ hashcpy(sha1, o->sha1);
596
+ if (sp[0] == '/') {
597
+ /* "$commit^{/foo}" */
598
+ char *prefix;
599
+ int ret;
600
+ struct commit_list *list = NULL;
601
+
602
+ prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1));
603
+ commit_list_insert((struct commit *)o, &list);
604
+ ret = get_sha1_oneline(prefix, sha1, list);
605
+ free(prefix);
606
+ return ret;
607
}
608
return 0;
609
}
t/t1511-rev-parse-caret.sh
new
+73
@@ -0,0 +1,73 @@
1
+#!/bin/sh
2
+
3
+test_description='tests for ref^{stuff}'
4
+
5
+. ./test-lib.sh
6
+
7
+test_expect_success 'setup' '
8
+ echo blob >a-blob &&
9
+ git tag -a -m blob blob-tag `git hash-object -w a-blob`
10
+ mkdir a-tree &&
11
+ echo moreblobs >a-tree/another-blob &&
12
+ git add . &&
13
+ TREE_SHA1=`git write-tree` &&
14
+ git tag -a -m tree tree-tag "$TREE_SHA1" &&
15
+ git commit -m Initial &&
16
+ git tag -a -m commit commit-tag &&
17
+ git branch ref &&
18
+ git checkout master &&
19
+ echo modified >>a-blob &&
20
+ git add -u &&
21
+ git commit -m Modified
22
+'
23
+
24
+test_expect_success 'ref^{non-existent}' '
25
+ test_must_fail git rev-parse ref^{non-existent}
26
+'
27
+
28
+test_expect_success 'ref^{}' '
29
+ git rev-parse ref >expected &&
30
+ git rev-parse ref^{} >actual &&
31
+ test_cmp expected actual &&
32
+ git rev-parse commit-tag^{} >actual &&
33
+ test_cmp expected actual
34
+'
35
+
36
+test_expect_success 'ref^{commit}' '
37
+ git rev-parse ref >expected &&
38
+ git rev-parse ref^{commit} >actual &&
39
+ test_cmp expected actual &&
40
+ git rev-parse commit-tag^{commit} >actual &&
41
+ test_cmp expected actual &&
42
+ test_must_fail git rev-parse tree-tag^{commit} &&
43
+ test_must_fail git rev-parse blob-tag^{commit}
44
+'
45
+
46
+test_expect_success 'ref^{tree}' '
47
+ echo $TREE_SHA1 >expected &&
48
+ git rev-parse ref^{tree} >actual &&
49
+ test_cmp expected actual &&
50
+ git rev-parse commit-tag^{tree} >actual &&
51
+ test_cmp expected actual &&
52
+ git rev-parse tree-tag^{tree} >actual &&
53
+ test_cmp expected actual &&
54
+ test_must_fail git rev-parse blob-tag^{tree}
55
+'
56
+
57
+test_expect_success 'ref^{/.}' '
58
+ git rev-parse master >expected &&
59
+ git rev-parse master^{/.} >actual &&
60
+ test_cmp expected actual
61
+'
62
+
63
+test_expect_success 'ref^{/non-existent}' '
64
+ test_must_fail git rev-parse master^{/non-existent}
65
+'
66
+
67
+test_expect_success 'ref^{/Initial}' '
68
+ git rev-parse ref >expected &&
69
+ git rev-parse master^{/Initial} >actual &&
70
+ test_cmp expected actual
71
+'
72
+
73
+test_done