]> git.proxmox.com Git - rustc.git/blob - vendor/gix/src/head/mod.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / gix / src / head / mod.rs
1 //!
2 use std::convert::TryInto;
3
4 use gix_hash::ObjectId;
5 use gix_ref::FullNameRef;
6
7 use crate::{
8 ext::{ObjectIdExt, ReferenceExt},
9 Head,
10 };
11
12 /// Represents the kind of `HEAD` reference.
13 #[derive(Clone)]
14 pub enum Kind {
15 /// The existing reference the symbolic HEAD points to.
16 ///
17 /// This is the common case.
18 Symbolic(gix_ref::Reference),
19 /// The yet-to-be-created reference the symbolic HEAD refers to.
20 ///
21 /// This is the case in a newly initialized repository.
22 Unborn(gix_ref::FullName),
23 /// The head points to an object directly, not to a symbolic reference.
24 ///
25 /// This state is less common and can occur when checking out commits directly.
26 Detached {
27 /// The object to which the head points to
28 target: ObjectId,
29 /// Possibly the final destination of `target` after following the object chain from tag objects to commits.
30 peeled: Option<ObjectId>,
31 },
32 }
33
34 impl Kind {
35 /// Attach this instance to a `repo` to produce a [`Head`].
36 pub fn attach(self, repo: &crate::Repository) -> Head<'_> {
37 Head { kind: self, repo }
38 }
39 }
40
41 /// Access
42 impl<'repo> Head<'repo> {
43 /// Returns the name of this references, always `HEAD`.
44 pub fn name(&self) -> &'static FullNameRef {
45 // TODO: use a statically checked version of this when available.
46 "HEAD".try_into().expect("HEAD is valid")
47 }
48
49 /// Returns the full reference name of this head if it is not detached, or `None` otherwise.
50 pub fn referent_name(&self) -> Option<&FullNameRef> {
51 Some(match &self.kind {
52 Kind::Symbolic(r) => r.name.as_ref(),
53 Kind::Unborn(name) => name.as_ref(),
54 Kind::Detached { .. } => return None,
55 })
56 }
57
58 /// Returns true if this instance is detached, and points to an object directly.
59 pub fn is_detached(&self) -> bool {
60 matches!(self.kind, Kind::Detached { .. })
61 }
62
63 /// Returns true if this instance is not yet born, hence it points to a ref that doesn't exist yet.
64 ///
65 /// This is the case in a newly initialized repository.
66 pub fn is_unborn(&self) -> bool {
67 matches!(self.kind, Kind::Unborn(_))
68 }
69
70 // TODO: tests
71 /// Returns the id the head points to, which isn't possible on unborn heads.
72 pub fn id(&self) -> Option<crate::Id<'repo>> {
73 match &self.kind {
74 Kind::Symbolic(r) => r.target.try_id().map(|oid| oid.to_owned().attach(self.repo)),
75 Kind::Detached { peeled, target } => {
76 (*peeled).unwrap_or_else(|| target.to_owned()).attach(self.repo).into()
77 }
78 Kind::Unborn(_) => None,
79 }
80 }
81
82 /// Try to transform this instance into the symbolic reference that it points to, or return `None` if head is detached or unborn.
83 pub fn try_into_referent(self) -> Option<crate::Reference<'repo>> {
84 match self.kind {
85 Kind::Symbolic(r) => r.attach(self.repo).into(),
86 _ => None,
87 }
88 }
89 }
90
91 mod remote {
92 use super::Head;
93 use crate::{remote, Remote};
94
95 /// Remote
96 impl<'repo> Head<'repo> {
97 /// Return the remote with which the currently checked our reference can be handled as configured by `branch.<name>.remote|pushRemote`
98 /// or fall back to the non-branch specific remote configuration. `None` is returned if the head is detached or unborn, so there is
99 /// no branch specific remote.
100 ///
101 /// This is equivalent to calling [`Reference::remote(…)`][crate::Reference::remote()] and
102 /// [`Repository::remote_default_name()`][crate::Repository::remote_default_name()] in order.
103 ///
104 /// Combine it with [`Repository::find_default_remote()`][crate::Repository::find_default_remote()] as fallback to
105 /// handle detached heads, i.e. obtain a remote even in case of detached heads,
106 /// or call [`Repository::find_fetch_remote(…)`](crate::Repository::find_fetch_remote()) for the highest-level way of finding
107 /// the right remote, just like `git fetch` does.
108 pub fn into_remote(
109 self,
110 direction: remote::Direction,
111 ) -> Option<Result<Remote<'repo>, remote::find::existing::Error>> {
112 let repo = self.repo;
113 self.try_into_referent()?
114 .remote(direction)
115 .or_else(|| repo.find_default_remote(direction))
116 }
117 }
118 }
119
120 ///
121 pub mod log;
122
123 ///
124 pub mod peel;