Skip to content

Commit cfaab7f

Browse files
committed
fix: Parse revisions with @ in their name (#802).
Previously these would cause a parse error due to confusing `@` with the short form of `HEAD`. Merge branch 'fix-rev-parse-with-at'
2 parents a884121 + c0905ce commit cfaab7f

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed

gix-revision/src/spec/parse/function.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,19 @@ where
344344
{
345345
let mut cursor = input;
346346
let mut ofs = 0;
347-
while let Some((pos, b)) = cursor.iter().enumerate().find(|(_, b)| {
348-
if b"@~^:.".contains(b) {
347+
const SEPARATORS: &[u8] = b"~^:.";
348+
while let Some((pos, b)) = cursor.iter().enumerate().find(|(pos, b)| {
349+
if **b == b'@' {
350+
if cursor.len() == 1 {
351+
return true;
352+
}
353+
let next = cursor.get(pos + 1);
354+
let next_next = cursor.get(pos + 2);
355+
if *pos != 0 && (next, next_next) == (Some(&b'.'), Some(&b'.')) {
356+
return false;
357+
}
358+
next == Some(&b'{') || next.map_or(false, |b| SEPARATORS.contains(b))
359+
} else if SEPARATORS.contains(b) {
349360
true
350361
} else {
351362
if let Some(num) = consecutive_hex_chars.as_mut() {

gix-revision/tests/spec/parse/anchor/refnames.rs

+28-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use gix_revision::spec;
2-
31
use crate::spec::parse::{parse, try_parse};
42

53
#[test]
@@ -10,15 +8,37 @@ fn at_by_itself_is_shortcut_for_head() {
108
}
119

1210
#[test]
13-
fn multiple_ats_are_invalid_but_may_cause_callbacks() {
14-
let err = try_parse("@@").unwrap_err();
15-
assert!(matches!(err, spec::parse::Error::AtNeedsCurlyBrackets {input} if input == "@"));
11+
fn at_is_allowed() {
12+
for name in ["a@b", "@branch", "branch@", "@@", "@inner@"] {
13+
let rec = parse(name);
14+
assert!(rec.kind.is_none());
15+
assert_eq!(rec.get_ref(0), name);
16+
assert_eq!(rec.find_ref[1], None);
17+
}
18+
}
19+
20+
#[test]
21+
fn at_in_ranges_is_allowed() {
22+
let input = "@@@..";
23+
let rec = parse(input);
24+
assert_eq!(rec.kind, Some(gix_revision::spec::Kind::RangeBetween));
25+
assert_eq!(rec.get_ref(0), "@@@");
26+
assert_eq!(rec.get_ref(1), "HEAD");
27+
28+
let input = "@@...@@";
29+
let rec = parse(input);
30+
assert_eq!(rec.kind, Some(gix_revision::spec::Kind::ReachableToMergeBase));
31+
assert_eq!(rec.get_ref(0), "@@");
32+
assert_eq!(rec.get_ref(1), "@@");
1633
}
1734

1835
#[test]
19-
fn lonely_at_after_ref_is_invalid() {
20-
let err = try_parse("HEAD@").unwrap_err();
21-
assert!(matches!(err, spec::parse::Error::AtNeedsCurlyBrackets {input} if input == "@"));
36+
fn strange_revspecs_do_not_panic() {
37+
let err = try_parse(".@.").unwrap_err();
38+
assert!(matches!(
39+
err,
40+
gix_revision::spec::parse::Error::AtNeedsCurlyBrackets { input } if input == "@."
41+
));
2242
}
2343

2444
#[test]

0 commit comments

Comments
 (0)