Skip to content

Commit fb79532

Browse files
committed
Merge branch 'wp/sha1-name-negative-match'
A new "<branch>^{/!-<pattern>}" notation can be used to name a commit that is reachable from <branch> that does not match the given <pattern>. * wp/sha1-name-negative-match: object name: introduce '^{/!-<negative pattern>}' notation test for '!' handling in rev-parse's named commits
2 parents 722c924 + 0769854 commit fb79532

File tree

3 files changed

+73
-11
lines changed

3 files changed

+73
-11
lines changed

Documentation/revisions.txt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,12 @@ existing tag object.
176176
A colon, followed by a slash, followed by a text, names
177177
a commit whose commit message matches the specified regular expression.
178178
This name returns the youngest matching commit which is
179-
reachable from any ref. If the commit message starts with a
180-
'!' you have to repeat that; the special sequence ':/!',
181-
followed by something else than '!', is reserved for now.
182-
The regular expression can match any part of the commit message. To
183-
match messages starting with a string, one can use e.g. ':/^foo'.
179+
reachable from any ref. The regular expression can match any part of the
180+
commit message. To match messages starting with a string, one can use
181+
e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what
182+
is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a
183+
literal '!' character, followed by 'foo'. Any other sequence beginning with
184+
':/!' is reserved for now.
184185

185186
'<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README'::
186187
A suffix ':' followed by a path names the blob or tree

sha1_name.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -848,8 +848,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
848848
* through history and returning the first commit whose message starts
849849
* the given regular expression.
850850
*
851-
* For future extension, ':/!' is reserved. If you want to match a message
852-
* beginning with a '!', you have to repeat the exclamation mark.
851+
* For negative-matching, prefix the pattern-part with '!-', like: ':/!-WIP'.
852+
*
853+
* For a literal '!' character at the beginning of a pattern, you have to repeat
854+
* that, like: ':/!!foo'
855+
*
856+
* For future extension, all other sequences beginning with ':/!' are reserved.
853857
*/
854858

855859
/* Remember to update object flag allocation in object.h */
@@ -878,12 +882,18 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
878882
{
879883
struct commit_list *backup = NULL, *l;
880884
int found = 0;
885+
int negative = 0;
881886
regex_t regex;
882887

883888
if (prefix[0] == '!') {
884-
if (prefix[1] != '!')
885-
die ("Invalid search pattern: %s", prefix);
886889
prefix++;
890+
891+
if (prefix[0] == '-') {
892+
prefix++;
893+
negative = 1;
894+
} else if (prefix[0] != '!') {
895+
die ("Invalid search pattern: %s", prefix);
896+
}
887897
}
888898

889899
if (regcomp(&regex, prefix, REG_EXTENDED))
@@ -903,7 +913,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
903913
continue;
904914
buf = get_commit_buffer(commit, NULL);
905915
p = strstr(buf, "\n\n");
906-
matches = p && !regexec(&regex, p + 2, 0, NULL, 0);
916+
matches = negative ^ (p && !regexec(&regex, p + 2, 0, NULL, 0));
907917
unuse_commit_buffer(commit, buf);
908918

909919
if (matches) {

t/t1511-rev-parse-caret.sh

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,18 @@ test_expect_success 'setup' '
1818
git checkout master &&
1919
echo modified >>a-blob &&
2020
git add -u &&
21-
git commit -m Modified
21+
git commit -m Modified &&
22+
git branch modref &&
23+
echo changed! >>a-blob &&
24+
git add -u &&
25+
git commit -m !Exp &&
26+
git branch expref &&
27+
echo changed >>a-blob &&
28+
git add -u &&
29+
git commit -m Changed &&
30+
echo changed-again >>a-blob &&
31+
git add -u &&
32+
git commit -m Changed-again
2233
'
2334

2435
test_expect_success 'ref^{non-existent}' '
@@ -77,4 +88,44 @@ test_expect_success 'ref^{/Initial}' '
7788
test_cmp expected actual
7889
'
7990

91+
test_expect_success 'ref^{/!Exp}' '
92+
test_must_fail git rev-parse master^{/!Exp}
93+
'
94+
95+
test_expect_success 'ref^{/!}' '
96+
test_must_fail git rev-parse master^{/!}
97+
'
98+
99+
test_expect_success 'ref^{/!!Exp}' '
100+
git rev-parse expref >expected &&
101+
git rev-parse master^{/!!Exp} >actual &&
102+
test_cmp expected actual
103+
'
104+
105+
test_expect_success 'ref^{/!-}' '
106+
test_must_fail git rev-parse master^{/!-}
107+
'
108+
109+
test_expect_success 'ref^{/!-.}' '
110+
test_must_fail git rev-parse master^{/!-.}
111+
'
112+
113+
test_expect_success 'ref^{/!-non-existent}' '
114+
git rev-parse master >expected &&
115+
git rev-parse master^{/!-non-existent} >actual &&
116+
test_cmp expected actual
117+
'
118+
119+
test_expect_success 'ref^{/!-Changed}' '
120+
git rev-parse expref >expected &&
121+
git rev-parse master^{/!-Changed} >actual &&
122+
test_cmp expected actual
123+
'
124+
125+
test_expect_success 'ref^{/!-!Exp}' '
126+
git rev-parse modref >expected &&
127+
git rev-parse expref^{/!-!Exp} >actual &&
128+
test_cmp expected actual
129+
'
130+
80131
test_done

0 commit comments

Comments
 (0)