Skip to main content

grit_lib/
hide_refs.rs

1//! `transfer.hideRefs` / `receive.hideRefs` / `uploadpack.hideRefs` matching (Git `ref_is_hidden`).
2
3/// Collect hide-ref patterns from config for receive-pack (transfer + receive).
4#[must_use]
5pub fn hide_ref_patterns_receive(config: &crate::config::ConfigSet) -> Vec<String> {
6    let mut v = config.get_all("transfer.hideRefs");
7    v.extend(config.get_all("receive.hideRefs"));
8    normalize_patterns(v)
9}
10
11/// Collect hide-ref patterns for upload-pack (transfer + uploadpack).
12#[must_use]
13pub fn hide_ref_patterns_uploadpack(config: &crate::config::ConfigSet) -> Vec<String> {
14    let mut v = config.get_all("transfer.hideRefs");
15    v.extend(config.get_all("uploadpack.hideRefs"));
16    normalize_patterns(v)
17}
18
19fn normalize_patterns(mut pats: Vec<String>) -> Vec<String> {
20    for p in &mut pats {
21        while p.ends_with('/') && p.len() > 1 {
22            p.pop();
23        }
24    }
25    pats
26}
27
28/// Whether `refname` (logical) / `refname_full` (storage) is hidden by `patterns`.
29///
30/// `patterns` are in config order; **later** entries win (matches Git's reverse scan).
31#[must_use]
32pub fn ref_is_hidden(refname: &str, refname_full: &str, patterns: &[String]) -> bool {
33    let mut i = patterns.len();
34    while i > 0 {
35        i -= 1;
36        let mut m = patterns[i].as_str();
37        let mut neg = false;
38        if let Some(rest) = m.strip_prefix('!') {
39            neg = true;
40            m = rest;
41        }
42        let subject = if let Some(rest) = m.strip_prefix('^') {
43            m = rest;
44            refname_full
45        } else {
46            refname
47        };
48        if subject.is_empty() {
49            continue;
50        }
51        if subject.starts_with(m)
52            && (m.is_empty()
53                || subject.len() == m.len()
54                || subject.as_bytes().get(m.len()) == Some(&b'/'))
55        {
56            return !neg;
57        }
58    }
59    false
60}