git_ref_format/
lib.rs

1// Copyright © 2021 The Radicle Link Contributors
2//
3// This file is part of radicle-link, distributed under the GPLv3 with Radicle
4// Linking Exception. For full terms see the included LICENSE file.
5
6//! Everything you never knew you wanted for handling git ref names.
7//!
8//! # Overview
9//!
10//! This crate provides a number of types which allow to validate git ref names,
11//! create new ones which are valid by construction, make assertions about their
12//! structure, and deconstruct them into their components.
13//!
14//! ## Basic Types
15//!
16//! The basic types are:
17//!
18//! * [`RefStr`]
19//! * [`RefString`]
20//!
21//! They are wrappers around [`str`] and [`String`] respectively, with the
22//! additional guarantee that they are also valid ref names as per
23//! [`git-check-ref-format`] (which is also exposed directly as
24//! [`check_ref_format`]). Both types are referred to as "ref strings".
25//!
26//! Note that this implies that ref names must be valid UTF-8, which git itself
27//! doesn't require.
28//!
29//! Ref strings can be iterated over, either yielding `&str` or [`Component`]. A
30//! [`Component`] is guaranteed to not contain a '/' separator, and can thus
31//! also be used to conveniently construct known-valid ref strings. The [`lit`]
32//! module contains a number of types (and `const` values thereof) which can be
33//! coerced into [`Component`], and thus can be used to construct known-valid
34//! ref strings.
35//!
36//! The [`name`] module also provides a number of constant values of commonly
37//! used ref strings / components, which are useful for pattern matching.
38//!
39//! The `"macro"` feature enables the `refstring!` and `component!` macros,
40//! which can be convenient to construct compile-time validated [`RefString`]s
41//! respectively [`Component`]s.
42//!
43//! ## Refspec Patterns
44//!
45//! The types
46//!
47//! * [`refspec::PatternStr`]
48//! * [`refspec::PatternString`]
49//!
50//! guarantee that their values are valid ref strings but additionally _may_
51//! contain at most one "*" character. It is thus possible to convert a ref
52//! string to a refspec pattern, but not the other way round. Refspec patterns
53//! are commonly used for mapping remote to local refs (cf. [`git-fetch`]).
54//!
55//! The `"macro"` feature enables the `refspec::pattern!` macro, which
56//! constructs a compile-time validated [`refspec::PatternString`].
57//!
58//! ## Structured Ref Strings
59//!
60//! Ref strings may be [`Qualified`], which essentially means that they start
61//! with "refs/". [`Qualified`] ref string also require at least three
62//! components (eg. "refs/heads/main"), which makes it easier to deal with
63//! common naming conventions.
64//!
65//! [`Qualified`] refs may be [`Namespaced`], or can be given a namespace
66//! (namespaces can be nested). [`Namespaced`] refs are also [`Qualified`], and
67//! can have their namespace(s) stripped.
68//!
69//! # On Git Ref Name Conventions
70//!
71//! Git references are essentially path names pointing to their traditional
72//! storage location in a the repository (`$GIT_DIR/refs`). Unlike (UNIX) file
73//! paths, they are subject to a few restrictions, as described in
74//! [`git-check-ref-format`].
75//!
76//! On top of that, there are a number of conventions around the hierarchical
77//! naming, _some_ of which are treated specially by tools such as the `git`
78//! CLI. For example:
79//!
80//! * `refs/heads/..` are also called "branches".
81//!
82//!   Omitting the "refs/heads/" prefix is typically accepted. Such a branch
83//!   name is also referred to as a "shorthand" ref.
84//!
85//! * `refs/tags/..` are assumed to contain tags.
86//!
87//!   `git` treats tags specially, specifically it insists that they be globally
88//!   unique across all   copies of the repository.
89//!
90//! * `refs/remotes/../..` is where "remote tracking branches" are stored.
91//!
92//!   In `git`, the first element after "remotes" is considered the name of the
93//!   [remote][git-remote] (as it appears in the config file), while everything
94//!   after that is considered a shorthand branch. Note, however, that the
95//!   remote name may itself contain '/' separators, so it is not generally
96//!   possible to extract  the branch name without access to the config.
97//!
98//! * `refs/namespaces/..` is hidden unless [`gitnamespaces`] are in effect.
99//!
100//!   The structure of namespaces is recursive: they contain full refs, which
101//!   can themselves be namespaces (eg.
102//!   `refs/namespaces/a/refs/namespaces/b/refs/heads/branch`). Note that,
103//!   unlike remote names,  namespace names can **not** contain forward slashes
104//!   but there is no tooling which would enforce that.
105//!
106//! There are also other such ref hierachies `git` knows about, and this crate
107//! doesn't attempt to cover all of them. More importantly, `git` does not
108//! impose any restrictions on ref hierarchies: as long as they don't collide
109//! with convential ones, applications can introduce any hierchies they want.
110//!
111//! This restricts the transformations between conventional refs which can be
112//! made without additional information besides the ref name: for example, it is
113//! not generally possible to turn a remote tracking branch into a branch (or a
114//! shorthand) without knowning about all possible remote names.
115//!
116//! Therefore, this crate doesn't attempt to interpret all possible semantics
117//! associated with refs, and instead tries to make it easy for library
118//! consumers to do so.
119//!
120//! [`git-check-ref-format`]: https://git-scm.com/docs/git-check-ref-format
121//! [`git-fetch`]: https://git-scm.com/docs/git-fetch
122//! [git-remote]: https://git-scm.com/docs/git-remote
123//! [`gitnamespaces`]: https://git-scm.com/docs/gitnamespaces
124#[cfg(feature = "percent-encoding")]
125pub use git_ref_format_core::PercentEncode;
126pub use git_ref_format_core::{
127    check_ref_format, lit, name::component, Component, DuplicateGlob, Error, Namespaced, Options,
128    Qualified, RefStr, RefString,
129};
130
131pub mod name {
132    pub use git_ref_format_core::name::*;
133
134    #[cfg(any(feature = "macro", feature = "git-ref-format-macro"))]
135    pub use git_ref_format_macro::component;
136}
137
138#[cfg(any(feature = "macro", feature = "git-ref-format-macro"))]
139pub use git_ref_format_macro::qualified;
140#[cfg(any(feature = "macro", feature = "git-ref-format-macro"))]
141pub use git_ref_format_macro::refname;
142
143pub mod refspec {
144    pub use git_ref_format_core::refspec::*;
145
146    #[cfg(any(feature = "macro", feature = "git-ref-format-macro"))]
147    pub use git_ref_format_macro::pattern;
148
149    #[cfg(any(feature = "macro", feature = "git-ref-format-macro"))]
150    pub use git_ref_format_macro::qualified_pattern;
151}