uv_git_types/
reference.rs

1use std::fmt::Display;
2use std::str;
3
4/// A reference to commit or commit-ish.
5#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
6pub enum GitReference {
7    /// A specific branch.
8    Branch(String),
9    /// A specific tag.
10    Tag(String),
11    /// From a reference that's ambiguously a branch or tag.
12    BranchOrTag(String),
13    /// From a reference that's ambiguously a commit, branch, or tag.
14    BranchOrTagOrCommit(String),
15    /// From a named reference, like `refs/pull/493/head`.
16    NamedRef(String),
17    /// The default branch of the repository, the reference named `HEAD`.
18    DefaultBranch,
19}
20
21impl GitReference {
22    /// Creates a [`GitReference`] from an arbitrary revision string, which could represent a
23    /// branch, tag, commit, or named ref.
24    pub fn from_rev(rev: String) -> Self {
25        if rev.starts_with("refs/") {
26            Self::NamedRef(rev)
27        } else if looks_like_commit_hash(&rev) {
28            Self::BranchOrTagOrCommit(rev)
29        } else {
30            Self::BranchOrTag(rev)
31        }
32    }
33
34    /// Converts the [`GitReference`] to a `str`.
35    pub fn as_str(&self) -> Option<&str> {
36        match self {
37            Self::Tag(rev) => Some(rev),
38            Self::Branch(rev) => Some(rev),
39            Self::BranchOrTag(rev) => Some(rev),
40            Self::BranchOrTagOrCommit(rev) => Some(rev),
41            Self::NamedRef(rev) => Some(rev),
42            Self::DefaultBranch => None,
43        }
44    }
45
46    /// Converts the [`GitReference`] to a `str` that can be used as a revision.
47    pub fn as_rev(&self) -> &str {
48        match self {
49            Self::Tag(rev) => rev,
50            Self::Branch(rev) => rev,
51            Self::BranchOrTag(rev) => rev,
52            Self::BranchOrTagOrCommit(rev) => rev,
53            Self::NamedRef(rev) => rev,
54            Self::DefaultBranch => "HEAD",
55        }
56    }
57
58    /// Returns the kind of this reference.
59    pub fn kind_str(&self) -> &str {
60        match self {
61            Self::Branch(_) => "branch",
62            Self::Tag(_) => "tag",
63            Self::BranchOrTag(_) => "branch or tag",
64            Self::BranchOrTagOrCommit(_) => "branch, tag, or commit",
65            Self::NamedRef(_) => "ref",
66            Self::DefaultBranch => "default branch",
67        }
68    }
69}
70
71impl Display for GitReference {
72    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73        write!(f, "{}", self.as_str().unwrap_or("HEAD"))
74    }
75}
76
77/// Whether a `rev` looks like a commit hash (ASCII hex digits).
78fn looks_like_commit_hash(rev: &str) -> bool {
79    rev.len() >= 7 && rev.chars().all(|ch| ch.is_ascii_hexdigit())
80}