Skip to content

Commit c4499ce

Browse files
committed
tests for handling exclusions (#450)
1 parent c99f575 commit c4499ce

File tree

4 files changed

+79
-40
lines changed

4 files changed

+79
-40
lines changed

git-refspec/src/parse.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub(crate) mod function {
7373

7474
let (src, src_had_pattern) = validated(src)?;
7575
let (dst, dst_had_pattern) = validated(dst)?;
76-
if src_had_pattern != dst_had_pattern {
76+
if mode != Mode::Negative && src_had_pattern != dst_had_pattern {
7777
return Err(Error::PatternUnbalanced);
7878
}
7979
Ok(RefSpecRef {

git-refspec/src/spec.rs

+48-36
Original file line numberDiff line numberDiff line change
@@ -14,48 +14,60 @@ impl RefSpecRef<'_> {
1414
fn has_pattern(item: &BStr) -> bool {
1515
item.contains(&b'*')
1616
}
17-
match (self.op, self.mode, self.src, self.dst) {
18-
(Operation::Fetch, Mode::Normal | Mode::Force, Some(src), None) => Instruction::Fetch(Fetch::Only { src }),
19-
(Operation::Fetch, Mode::Normal | Mode::Force, Some(src), Some(dst)) => {
20-
Instruction::Fetch(Fetch::AndUpdateSingle {
17+
match self.op {
18+
Operation::Fetch => match (self.mode, self.src, self.dst) {
19+
(Mode::Normal | Mode::Force, Some(src), None) => Instruction::Fetch(Fetch::Only { src }),
20+
(Mode::Normal | Mode::Force, Some(src), Some(dst)) => Instruction::Fetch(Fetch::AndUpdateSingle {
2121
src,
2222
dst,
2323
allow_non_fast_forward: matches!(self.mode, Mode::Force),
24-
})
25-
}
26-
(Operation::Push, Mode::Normal | Mode::Force, Some(src), None) => Instruction::Push(Push::Single {
27-
src,
28-
dst: src,
29-
allow_non_fast_forward: matches!(self.mode, Mode::Force),
30-
}),
31-
(Operation::Push, Mode::Normal | Mode::Force, None, Some(dst)) => {
32-
Instruction::Push(Push::Delete { ref_or_pattern: dst })
33-
}
34-
(Operation::Push, Mode::Normal | Mode::Force, None, None) => Instruction::Push(Push::AllMatchingBranches {
35-
allow_non_fast_forward: matches!(self.mode, Mode::Force),
36-
}),
37-
(Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dst)) if has_pattern(src) => {
38-
Instruction::Push(Push::MultipleWithGlob {
24+
}),
25+
(Mode::Negative, Some(src), None) if has_pattern(src) => {
26+
Instruction::Fetch(Fetch::ExcludeMultipleWithGlob { src })
27+
}
28+
(Mode::Negative, Some(src), None) => Instruction::Fetch(Fetch::ExcludeSingle { src }),
29+
(mode, src, dest) => {
30+
unreachable!(
31+
"BUG: fetch instructions with {:?} {:?} {:?} are not possible",
32+
mode, src, dest
33+
)
34+
}
35+
},
36+
Operation::Push => match (self.mode, self.src, self.dst) {
37+
(Mode::Normal | Mode::Force, Some(src), None) => Instruction::Push(Push::Single {
38+
src,
39+
dst: src,
40+
allow_non_fast_forward: matches!(self.mode, Mode::Force),
41+
}),
42+
(Mode::Normal | Mode::Force, None, Some(dst)) => {
43+
Instruction::Push(Push::Delete { ref_or_pattern: dst })
44+
}
45+
(Mode::Normal | Mode::Force, None, None) => Instruction::Push(Push::AllMatchingBranches {
46+
allow_non_fast_forward: matches!(self.mode, Mode::Force),
47+
}),
48+
(Mode::Normal | Mode::Force, Some(src), Some(dst)) if has_pattern(src) => {
49+
Instruction::Push(Push::MultipleWithGlob {
50+
src,
51+
dst,
52+
allow_non_fast_forward: matches!(self.mode, Mode::Force),
53+
})
54+
}
55+
(Mode::Normal | Mode::Force, Some(src), Some(dst)) => Instruction::Push(Push::Single {
3956
src,
4057
dst,
4158
allow_non_fast_forward: matches!(self.mode, Mode::Force),
42-
})
43-
}
44-
(Operation::Push, Mode::Normal | Mode::Force, Some(src), Some(dst)) => Instruction::Push(Push::Single {
45-
src,
46-
dst,
47-
allow_non_fast_forward: matches!(self.mode, Mode::Force),
48-
}),
49-
(Operation::Push, Mode::Negative, Some(src), None) if has_pattern(src) => {
50-
Instruction::Push(Push::ExcludeMultipleWithGlob { src })
51-
}
52-
(Operation::Push, Mode::Negative, Some(src), None) => Instruction::Push(Push::ExcludeSingle { src }),
53-
(op, mode, src, dest) => {
54-
unreachable!(
55-
"BUG: instructions with {:?} {:?} {:?} {:?} are not possible",
56-
op, mode, src, dest
57-
)
58-
}
59+
}),
60+
(Mode::Negative, Some(src), None) if has_pattern(src) => {
61+
Instruction::Push(Push::ExcludeMultipleWithGlob { src })
62+
}
63+
(Mode::Negative, Some(src), None) => Instruction::Push(Push::ExcludeSingle { src }),
64+
(mode, src, dest) => {
65+
unreachable!(
66+
"BUG: push instructions with {:?} {:?} {:?} are not possible",
67+
mode, src, dest
68+
)
69+
}
70+
},
5971
}
6072
}
6173
}

git-refspec/src/types.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub enum Instruction<'a> {
2626
Fetch(Fetch<'a>),
2727
}
2828

29+
/// Note that all sources can either be a ref-name, partial or full, or a rev-spec. Destinations can only be a partial or full ref name.
2930
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
3031
pub enum Push<'a> {
3132
/// Push all local branches to the matching destination on the remote, which has to exist to be updated.
@@ -59,7 +60,7 @@ pub enum Push<'a> {
5960
},
6061
/// Push a multiple refs to matching destination refs, with exactly a single glob on both sides.
6162
MultipleWithGlob {
62-
/// The source ref to match against all refs for pushing.
63+
/// The source ref to match against all refs for pushing, as pattern with a single `*`.
6364
src: &'a BStr,
6465
/// The ref to update with object obtained from `src`, filling in the `*` with the portion that matched in `src`.
6566
dst: &'a BStr,
@@ -68,10 +69,13 @@ pub enum Push<'a> {
6869
},
6970
}
7071

72+
/// Note that any source can either be a ref name (full or partial) or a fully spelled out hex-sha for an object.
73+
///
74+
/// Destinations can only be a partial or full ref-name.
7175
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
7276
pub enum Fetch<'a> {
7377
Only {
74-
/// The ref name to fetch on the remote side, without updating the local side.
78+
/// The ref name to fetch on the remote side, without updating the local side. This will write the result into `FETCH_HEAD`.
7579
src: &'a BStr,
7680
},
7781
/// Exclude a single ref.
@@ -94,7 +98,7 @@ pub enum Fetch<'a> {
9498
},
9599
/// Similar to `FetchAndUpdate`, but src and destination contain a single glob to fetch and update multiple refs.
96100
AndUpdateMultipleWithGlob {
97-
/// The ref glob to match against all refs on the remote side for fetching.
101+
/// The ref glob to match against all refs on the remote side for fetching, as pattern with a single `*`.
98102
src: &'a BStr,
99103
/// The local destination to update with what was fetched by replacing the single `*` with the matching portion from `src`.
100104
dst: &'a BStr,

git-refspec/tests/parse/mod.rs

+23
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@ mod fetch {
108108
use crate::parse::{assert_parse, b};
109109
use git_refspec::{Fetch, Instruction, Mode};
110110

111+
#[test]
112+
fn exclude_single() {
113+
assert_parse("^a", Instruction::Fetch(Fetch::ExcludeSingle { src: b("a") }));
114+
}
115+
116+
#[test]
117+
fn exclude_multiple() {
118+
assert_parse(
119+
"^a*",
120+
Instruction::Fetch(Fetch::ExcludeMultipleWithGlob { src: b("a*") }),
121+
);
122+
}
123+
111124
#[test]
112125
fn lhs_colon_empty_fetches_only() {
113126
assert_parse("src:", Instruction::Fetch(Fetch::Only { src: b("src") }));
@@ -157,6 +170,16 @@ mod push {
157170
use crate::parse::{assert_parse, b};
158171
use git_refspec::{Instruction, Mode, Push};
159172

173+
#[test]
174+
fn exclude_single() {
175+
assert_parse("^a", Instruction::Push(Push::ExcludeSingle { src: b("a") }));
176+
}
177+
178+
#[test]
179+
fn exclude_multiple() {
180+
assert_parse("^a*", Instruction::Push(Push::ExcludeMultipleWithGlob { src: b("a*") }));
181+
}
182+
160183
#[test]
161184
fn colon_alone_is_for_pushing_matching_refs() {
162185
assert_parse(

0 commit comments

Comments
 (0)