History

[ref] refactor

Sebastian Thiel committed 5 years ago

Commit e26c72f1 parent f4bb7a019 files · +167 −226Browse files

Unified · Split

19 files
  1. git-object/tests/immutable/tag.rs +4 −1
  2. git-ref/src/mutable.rs +5 −0
  3. git-ref/src/store/file/loose/find.rs +6 −4
  4. git-ref/src/store/file/loose/iter.rs +30 −46
  5. git-ref/src/store/file/mod.rs +3 −3
  6. git-ref/src/store/file/overlay/iter.rs +10 −8
  7. git-ref/src/store/file/overlay/reference.rs +7 −17
  8. git-ref/src/store/file/reference/decode.rs +3 −10
  9. git-ref/src/store/file/reference/logiter.rs +4 −14
  10. git-ref/src/store/file/reference/mod.rs +1 −36
  11. git-ref/src/store/file/reference/peel.rs +3 −3
  12. git-ref/src/store/file/transaction.rs +12 −10
  13. git-ref/tests/file/reference.rs +24 −18
  14. git-ref/tests/file/store/find.rs +4 −5
  15. git-ref/tests/file/store/iter.rs +7 −7
  16. git-ref/tests/file/transaction/prepare_and_commit/create_or_update.rs +15 −15
  17. git-ref/tests/file/transaction/prepare_and_commit/delete.rs +20 −20
  18. git-ref/tests/packed/find.rs +5 −5
  19. git-repository/src/path/is_git.rs +4 −4
git-object/tests/immutable/tag.rs+4−1
@@ -9,7 +9,10 @@ mod method { · 8 unmodified lines
99 fn target() -> crate::Result {
1010 let fixture = fixture_bytes("tag", "signed.txt");
1111 let tag = Tag::from_bytes(&fixture)?;
12− assert_eq!(tag.target(), hex_to_id("ffa700b4aca13b80cb6b98a078e7c96804f8e0ec"));
12+ assert_eq!(
13+ tag.target.borrow(),
14+ hex_to_id("ffa700b4aca13b80cb6b98a078e7c96804f8e0ec")
15+ );
1316 assert_eq!(tag.target, "ffa700b4aca13b80cb6b98a078e7c96804f8e0ec".as_bytes());
1417 Ok(())
1518 }
git-ref/src/mutable.rs+5−0
@@ -33,6 +33,7 @@ impl TryFrom<BString> for FullName { · 32 unmodified lines
3333 }
3434 }
3535
36+// TODO: remove this one to be consistent with borrowed version
3637 impl AsRef<BStr> for FullName {
3738 fn as_ref(&self) -> &BStr {
3839 self.0.as_bstr()
@@ -59,6 +60,10 @@ impl FullName { · 20 unmodified lines
5960 pub fn into_inner(self) -> BString {
6061 self.0
6162 }
63+ /// Return ourselves as byte string which is a valid refname
64+ pub fn as_bstr(&self) -> &BStr {
65+ self.0.as_bstr()
66+ }
6267 }
6368
6469 /// Denotes a ref target, equivalent to [`Kind`][super::Kind], but with mutable data.
git-ref/src/store/file/loose/find.rs+6−4
@@ -119,11 +119,12 @@ impl file::Store { · 118 unmodified lines
119119 }
120120 Some(c) => c,
121121 };
122− Ok(Some(
123− file::Reference::try_from_path(self, &relative_path, &contents)
122+ Ok(Some({
123+ let full_name = path_to_name(&relative_path);
124+ file::Reference::try_from_path(self, FullName(full_name), &contents)
124125 .map(file::loose_then_packed::Reference::Loose)
125− .map_err(|err| Error::ReferenceCreation { err, relative_path })?,
126− ))
126+ .map_err(|err| Error::ReferenceCreation { err, relative_path })?
127+ }))
127128 }
128129 }
129130
@@ -256,4 +257,5 @@ mod error { · 126 unmodified lines
256257 }
257258 }
258259 }
260+use crate::mutable::FullName;
259261 pub use error::Error;
git-ref/src/store/file/loose/iter.rs+30−46
@@ -1,5 +1,5 @@
1−use crate::store::file;
2−use bstr::{BString, ByteSlice};
1+use crate::{mutable::FullName, store::file};
2+use bstr::ByteSlice;
33 use git_features::fs::walkdir::DirEntryIter;
44 use os_str_bytes::OsStrBytes;
55 use std::{
@@ -11,31 +11,20 @@ use std::{ · 5 unmodified lines
1111 pub(in crate::store::file) struct SortedLoosePaths {
1212 base: PathBuf,
1313 file_walk: DirEntryIter,
14− mode: LoosePathsMode,
15−}
16−
17−enum LoosePathsMode {
18− Paths,
19− PathsAndNames,
2014 }
2115
2216 impl SortedLoosePaths {
23− pub fn at_root(path: impl AsRef<Path>, base: impl Into<PathBuf>) -> Self {
24− Self::new(path.as_ref(), base.into(), LoosePathsMode::Paths)
25− }
26−
2717 pub fn at_root_with_names(path: impl AsRef<Path>, base: impl Into<PathBuf>) -> Self {
28− Self::new(path.as_ref(), base.into(), LoosePathsMode::PathsAndNames)
29− }
30−
31− fn new(path: &Path, base: PathBuf, mode: LoosePathsMode) -> Self {
3218 let file_walk = git_features::fs::walkdir_sorted_new(path).into_iter();
33− SortedLoosePaths { base, file_walk, mode }
19+ SortedLoosePaths {
20+ base: base.into(),
21+ file_walk,
22+ }
3423 }
3524 }
3625
3726 impl Iterator for SortedLoosePaths {
38− type Item = std::io::Result<(PathBuf, Option<BString>)>;
27+ type Item = std::io::Result<(PathBuf, FullName)>;
3928
4029 fn next(&mut self) -> Option<Self::Item> {
4130 while let Some(entry) = self.file_walk.next() {
@@ -52,15 +41,11 @@ impl Iterator for SortedLoosePaths { · 10 unmodified lines
5241 #[cfg(windows)]
5342 let full_name: Vec<u8> = full_name.into_owned().replace(b"\\", b"/");
5443
55− use LoosePathsMode::*;
5644 if git_validate::reference::name_partial(full_name.as_bstr()).is_ok() {
57− let name = match self.mode {
58− Paths => None,
59− #[cfg(not(windows))]
60− PathsAndNames => Some(full_name.into_owned().into()),
61− #[cfg(windows)]
62− PathsAndNames => Some(full_name.into()),
63− };
45+ #[cfg(not(windows))]
46+ let name = FullName(full_name.into_owned().into());
47+ #[cfg(windows)]
48+ let name = FullName(full_name.into());
6449 return Some(Ok((full_path, name)));
6550 } else {
6651 continue;
@@ -86,7 +71,7 @@ impl<'a> Loose<'a> { · 19 unmodified lines
8671 pub fn at_root(store: &'a file::Store, root: impl AsRef<Path>, base: impl Into<PathBuf>) -> Self {
8772 Loose {
8873 parent: store,
89− ref_paths: SortedLoosePaths::at_root(root, base),
74+ ref_paths: SortedLoosePaths::at_root_with_names(root, base),
9075 buf: Vec::new(),
9176 }
9277 }
@@ -97,26 +82,25 @@ impl<'a> Iterator for Loose<'a> { · 4 unmodified lines
9782
9883 fn next(&mut self) -> Option<Self::Item> {
9984 self.ref_paths.next().map(|res| {
100− res.map_err(loose::Error::Traversal)
101− .and_then(|(validated_path, _name)| {
102− std::fs::File::open(&validated_path)
103− .and_then(|mut f| {
104− self.buf.clear();
105− f.read_to_end(&mut self.buf)
106− })
107− .map_err(loose::Error::ReadFileContents)
108− .and_then(|_| {
109− let relative_path = validated_path
110− .strip_prefix(&self.ref_paths.base)
111− .expect("root contains path");
112− file::Reference::try_from_path(self.parent, relative_path, &self.buf).map_err(|err| {
113− loose::Error::ReferenceCreation {
114− err,
115− relative_path: relative_path.into(),
116− }
117− })
85+ res.map_err(loose::Error::Traversal).and_then(|(validated_path, name)| {
86+ std::fs::File::open(&validated_path)
87+ .and_then(|mut f| {
88+ self.buf.clear();
89+ f.read_to_end(&mut self.buf)
90+ })
91+ .map_err(loose::Error::ReadFileContents)
92+ .and_then(|_| {
93+ let relative_path = validated_path
94+ .strip_prefix(&self.ref_paths.base)
95+ .expect("root contains path");
96+ file::Reference::try_from_path(self.parent, name, &self.buf).map_err(|err| {
97+ loose::Error::ReferenceCreation {
98+ err,
99+ relative_path: relative_path.into(),
100+ }
118101 })
119− })
102+ })
103+ })
120104 })
121105 }
122106 }
git-ref/src/store/file/mod.rs+3−3
@@ -21,9 +21,9 @@ impl Default for WriteReflog { · 20 unmodified lines
2121 pub struct Reference<'a> {
2222 parent: &'a Store,
2323 /// The path to uniquely identify this ref within its store.
24− // TODO: make this a FullName(BString) and remove the `relative_path()` method entirely.
25− relative_path: PathBuf,
26− target: mutable::Target,
24+ pub name: mutable::FullName,
25+ /// The target of the reference, either a symbolic reference by full name or an object by its id.
26+ pub target: mutable::Target,
2727 }
2828
2929 /// A store for reference which uses plain files.
git-ref/src/store/file/overlay/iter.rs+10−8
@@ -3,7 +3,6 @@ use crate::{ · 2 unmodified lines
33 file::path_to_name,
44 store::{file, packed},
55 };
6−use bstr::BString;
76 use std::{
87 cmp::Ordering,
98 io::Read,
@@ -27,19 +26,21 @@ impl<'p, 's> LooseThenPacked<'p, 's> { · 17 unmodified lines
2726 })
2827 }
2928
30− fn convert_loose(&mut self, res: std::io::Result<(PathBuf, Option<BString>)>) -> Result<Reference<'p, 's>, Error> {
31− let (refpath, _name) = res.map_err(Error::Traversal)?;
29+ fn convert_loose(&mut self, res: std::io::Result<(PathBuf, FullName)>) -> Result<Reference<'p, 's>, Error> {
30+ let (refpath, name) = res.map_err(Error::Traversal)?;
3231 std::fs::File::open(&refpath)
3332 .and_then(|mut f| {
3433 self.buf.clear();
3534 f.read_to_end(&mut self.buf)
3635 })
3736 .map_err(Error::ReadFileContents)?;
38− let relative_path = refpath.strip_prefix(&self.parent.base).expect("base contains path");
39− file::Reference::try_from_path(self.parent, relative_path, &self.buf)
37+ file::Reference::try_from_path(self.parent, name, &self.buf)
4038 .map_err(|err| Error::ReferenceCreation {
4139 err,
42− relative_path: relative_path.into(),
40+ relative_path: refpath
41+ .strip_prefix(&self.parent.base)
42+ .expect("base contains path")
43+ .into(),
4344 })
4445 .map(Reference::Loose)
4546 }
@@ -60,8 +61,8 @@ impl<'p, 's> Iterator for LooseThenPacked<'p, 's> { · 14 unmodified lines
6061 Some(self.convert_loose(res))
6162 }
6263 (Some(Ok(loose)), Some(Ok(packed))) => {
63− let loose_name = loose.1.as_ref().expect("name retrieval configured");
64− match loose_name.as_slice().cmp(packed.full_name) {
64+ let loose_name = loose.1.as_ref();
65+ match loose_name.cmp(packed.full_name) {
6566 Ordering::Less => {
6667 let res = self.loose.next().expect("name retrieval configured");
6768 Some(self.convert_loose(res))
@@ -154,4 +155,5 @@ mod error { · 86 unmodified lines
154155 }
155156 }
156157
158+use crate::mutable::FullName;
157159 pub use error::Error;
git-ref/src/store/file/overlay/reference.rs+7−17
@@ -1,16 +1,14 @@
11 use super::Reference;
22 use crate::{
3− mutable,
3+ mutable, name,
44 store::{
55 file::{log, loose},
66 packed,
77 },
8+ FullName,
89 };
910 use git_hash::oid;
10−use std::{
11− convert::{TryFrom, TryInto},
12− path::Path,
13−};
11+use std::convert::{TryFrom, TryInto};
1412
1513 impl<'p, 's> TryFrom<Reference<'p, 's>> for crate::file::Reference<'s> {
1614 type Error = ();
@@ -32,14 +30,6 @@ impl<'p, 's> Reference<'p, 's> { · 15 unmodified lines
3230 }
3331 }
3432
35− /// Return the full name of this reference as path, only applicable if this is a loose reference.
36− pub fn relative_path(&self) -> Option<&Path> {
37− match self {
38− Reference::Loose(r) => Some(r.relative_path()),
39− Reference::Packed(_) => None,
40− }
41− }
42−
4333 /// For details, see [crate::file::Reference::peel_to_id_in_place].
4434 pub fn peel_to_id_in_place(
4535 &mut self,
@@ -96,7 +86,7 @@ impl<'p, 's> Reference<'p, 's> { · 50 unmodified lines
9686 pub fn into_target(self) -> mutable::Target {
9787 match self {
9888 Reference::Packed(p) => mutable::Target::Peeled(p.object()),
99− Reference::Loose(r) => r.into_target(),
89+ Reference::Loose(r) => r.target,
10090 }
10191 }
10292
@@ -109,10 +99,10 @@ impl<'p, 's> Reference<'p, 's> { · 6 unmodified lines
10999 }
110100
111101 /// Return the full validated name of the reference. Please note that if the reference is packed, validation can fail here.
112− pub fn name(&self) -> Result<mutable::FullName, git_validate::refname::Error> {
102+ pub fn name(&self) -> Result<FullName<'_>, name::Error> {
113103 match self {
114104 Reference::Packed(p) => p.full_name.try_into(),
115− Reference::Loose(l) => Ok(l.name()),
105+ Reference::Loose(l) => Ok(l.name.borrow()),
116106 }
117107 }
118108
@@ -120,7 +110,7 @@ impl<'p, 's> Reference<'p, 's> { · 1 unmodified line
120110 pub fn target(&self) -> mutable::Target {
121111 match self {
122112 Reference::Packed(p) => mutable::Target::Peeled(p.target()),
123− Reference::Loose(l) => l.target().to_owned(),
113+ Reference::Loose(l) => l.target.clone(),
124114 }
125115 }
126116 }
git-ref/src/store/file/reference/decode.rs+3−10
@@ -12,10 +12,7 @@ use nom::{ · 11 unmodified lines
1212 IResult,
1313 };
1414 use quick_error::quick_error;
15−use std::{
16− convert::{TryFrom, TryInto},
17− path::PathBuf,
18−};
15+use std::convert::{TryFrom, TryInto};
1916
2017 enum MaybeUnsafeState {
2118 Id(ObjectId),
@@ -56,14 +53,10 @@ impl TryFrom<MaybeUnsafeState> for mutable::Target { · 34 unmodified lines
5653 impl<'a> Reference<'a> {
5754 /// Create a new reference of the given `parent` store with `relative_path` service as unique identifier
5855 /// at which the `path_contents` was read to obtain the refs value.
59− pub fn try_from_path(
60− parent: &'a Store,
61− relative_path: impl Into<PathBuf>,
62− path_contents: &[u8],
63− ) -> Result<Self, Error> {
56+ pub fn try_from_path(parent: &'a Store, name: mutable::FullName, path_contents: &[u8]) -> Result<Self, Error> {
6457 Ok(Reference {
6558 parent,
66− relative_path: relative_path.into(),
59+ name,
6760 target: parse(path_contents)
6861 .map_err(|_| Error::Parse(path_contents.into()))?
6962 .1
git-ref/src/store/file/reference/logiter.rs+4−14
@@ -1,8 +1,4 @@
1−use crate::{
2− store::file::{log, loose, Reference},
3− FullName,
4−};
5−use bstr::ByteSlice;
1+use crate::store::file::{log, loose, Reference};
62 use std::io::Read;
73
84 impl<'a> Reference<'a> {
@@ -13,9 +9,7 @@ impl<'a> Reference<'a> { · 4 unmodified lines
139 /// If the caller needs to know if it's readable, try to read the log instead with a reverse or forward iterator.
1410 pub fn log_exists(&self) -> Result<bool, loose::reflog::Error> {
1511 // NOTE: Have to repeat the implementation of store::reflog_iter here as borrow_check believes impl Iterator binds self
16− use os_str_bytes::OsStrBytes;
17− let name = self.relative_path.as_path().to_raw_bytes();
18− Ok(self.parent.reflog_path(FullName(name.as_bstr())).is_file())
12+ Ok(self.parent.reflog_path(self.name.borrow()).is_file())
1913 }
2014 /// Return a reflog reverse iterator for this ref, reading chunks from the back into the fixed buffer `buf`.
2115 ///
@@ -26,9 +20,7 @@ impl<'a> Reference<'a> { · 4 unmodified lines
2620 buf: &'b mut [u8],
2721 ) -> Result<Option<log::iter::Reverse<'b, std::fs::File>>, loose::reflog::Error> {
2822 // NOTE: Have to repeat the implementation of store::reflog_iter here as borrow_check believes impl Iterator binds self
29− use os_str_bytes::OsStrBytes;
30− let name = self.relative_path.as_path().to_raw_bytes();
31− let file = match std::fs::File::open(self.parent.reflog_path(FullName(name.as_bstr()))) {
23+ let file = match std::fs::File::open(self.parent.reflog_path(self.name.borrow())) {
3224 Ok(file) => file,
3325 Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
3426 Err(err) => return Err(err.into()),
@@ -46,9 +38,7 @@ impl<'a> Reference<'a> { · 11 unmodified lines
4638 ) -> Result<Option<impl Iterator<Item = Result<log::Line<'b>, log::iter::decode::Error>>>, loose::reflog::Error>
4739 {
4840 // NOTE: Have to repeat the implementation of store::reflog_iter here as borrow_check believes impl Iterator binds self
49− use os_str_bytes::OsStrBytes;
50− let name = self.relative_path.as_path().to_raw_bytes();
51− match std::fs::File::open(self.parent.reflog_path(FullName(name.as_bstr()))) {
41+ match std::fs::File::open(self.parent.reflog_path(self.name.borrow())) {
5242 Ok(mut file) => {
5343 buf.clear();
5444 file.read_to_end(buf)?;
git-ref/src/store/file/reference/mod.rs+1−36
@@ -1,45 +1,10 @@
1−use crate::{file::Reference, mutable, mutable::FullName, Kind, Target};
2−use std::path::{Path, PathBuf};
1+use crate::{file::Reference, Kind};
32
43 impl<'a> Reference<'a> {
54 /// Return the kind of ref.
65 pub fn kind(&self) -> Kind {
76 self.target.kind()
87 }
9−
10− /// Return the target to which this instance is pointing.
11− pub fn target(&self) -> Target<'_> {
12− self.target.borrow()
13− }
14−
15− /// Transform this reference into an owned `Target`
16− pub fn into_target(self) -> mutable::Target {
17− self.target
18− }
19−
20− /// Return the full name of this reference as path.
21− ///
22− /// Use [`name()`][Reference::name()] if consistent component separators are required across platforms.
23− pub fn relative_path(&self) -> &Path {
24− &self.relative_path
25− }
26−
27− /// Return our relative path while consuming this instance
28− pub fn into_relative_path(self) -> PathBuf {
29− self.relative_path
30− }
31−
32− /// Return the full validated name of the reference
33− pub fn name(&self) -> FullName {
34− use os_str_bytes::OsStrBytes;
35− let name = self.relative_path.as_path().to_raw_bytes();
36− #[cfg(windows)]
37− let name = {
38− use bstr::ByteSlice;
39− name.replace(b"\\", b"/")
40− };
41− FullName(name.to_vec().into())
42− }
438 }
449
4510 mod logiter;
git-ref/src/store/file/reference/peel.rs+3−3
@@ -98,10 +98,10 @@ pub mod to_id { · 97 unmodified lines
9898 loose_then_packed::Reference::Loose(r) => r,
9999 loose_then_packed::Reference::Packed(_) => unreachable!("handled above - we are done"),
100100 };
101− if seen.contains(&cursor.relative_path) {
102− return Err(Error::Cycle(cursor.parent.base.join(&cursor.relative_path)));
101+ if seen.contains(&cursor.name) {
102+ return Err(Error::Cycle(cursor.parent.base.join(cursor.name.to_path())));
103103 }
104− seen.insert(cursor.relative_path.clone());
104+ seen.insert(cursor.name.clone());
105105 count += 1;
106106 const MAX_REF_DEPTH: usize = 5;
107107 if count == MAX_REF_DEPTH {
git-ref/src/store/file/transaction.rs+12−10
@@ -60,8 +60,10 @@ impl<'a> Transaction<'a> { · 59 unmodified lines
6060 .ref_contents(relative_path.as_ref())
6161 .map_err(Error::from)
6262 .and_then(|opt| {
63− opt.map(|buf| file::Reference::try_from_path(store, relative_path.as_ref(), &buf).map_err(Error::from))
64− .transpose()
63+ opt.map(|buf| {
64+ file::Reference::try_from_path(store, change.update.name.clone(), &buf).map_err(Error::from)
65+ })
66+ .transpose()
6567 })
6668 .or_else(|err| match err {
6769 Error::ReferenceDecode(_) => Ok(None),
@@ -87,12 +89,12 @@ impl<'a> Transaction<'a> { · 19 unmodified lines
8789 })
8890 }
8991 (Some(previous), Some(existing)) => {
90− if !previous.is_null() && *previous != existing.target() {
92+ if !previous.is_null() && *previous != existing.target {
9193 let expected = previous.clone();
9294 return Err(Error::ReferenceOutOfDate {
9395 full_name: change.name(),
9496 expected,
95− actual: existing.target().to_owned(),
97+ actual: existing.target.to_owned(),
9698 });
9799 }
98100 }
@@ -100,7 +102,7 @@ impl<'a> Transaction<'a> { · 1 unmodified line
100102
101103 // Keep the previous value for the caller and ourselves. Maybe they want to keep a log of sorts.
102104 if let Some(existing) = existing_ref {
103− *previous = Some(existing.target().into());
105+ *previous = Some(existing.target.into());
104106 }
105107
106108 lock
@@ -120,11 +122,11 @@ impl<'a> Transaction<'a> { · 13 unmodified lines
120122
121123 let existing_ref = existing_ref?;
122124 match (&previous, &existing_ref) {
123− (Create::Only, Some(existing)) if existing.target() != new.borrow() => {
125+ (Create::Only, Some(existing)) if existing.target != new.borrow() => {
124126 let new = new.clone();
125127 return Err(Error::MustNotExist {
126128 full_name: change.name(),
127− actual: existing.target().to_owned(),
129+ actual: existing.target.to_owned(),
128130 new,
129131 });
130132 }
@@ -135,9 +137,9 @@ impl<'a> Transaction<'a> { · 4 unmodified lines
135137 Some(existing),
136138 ) => match previous {
137139 Target::Peeled(oid) if oid.is_null() => {}
138− any_target if any_target.borrow() == existing.target() => {}
140+ any_target if *any_target == existing.target => {}
139141 _target_mismatch => {
140− let actual = existing.target().to_owned();
142+ let actual = existing.target.to_owned();
141143 let expected = previous.to_owned();
142144 let full_name = change.name();
143145 return Err(Error::ReferenceOutOfDate {
@@ -163,7 +165,7 @@ impl<'a> Transaction<'a> { · 19 unmodified lines
163165 *previous = match existing_ref {
164166 None => Create::Only,
165167 Some(existing) => Create::OrUpdate {
166− previous: Some(existing.target().into()),
168+ previous: Some(existing.target.into()),
167169 },
168170 };
169171
git-ref/tests/file/reference.rs+24−18
@@ -4,7 +4,7 @@ mod reflog { · 3 unmodified lines
44 #[test]
55 fn iter() -> crate::Result {
66 let store = file::store()?;
7− let r = store.find_existing("HEAD", None)?;
7+ let r = store.loose_find_existing("HEAD")?;
88 let mut buf = Vec::new();
99 assert_eq!(r.log_iter(&mut buf)?.expect("log exists").count(), 1);
1010 Ok(())
@@ -13,7 +13,7 @@ mod reflog { · 2 unmodified lines
1313 #[test]
1414 fn iter_rev() -> crate::Result {
1515 let store = file::store()?;
16− let r = store.find_existing("HEAD", None)?;
16+ let r = store.loose_find_existing("HEAD")?;
1717 let mut buf = [0u8; 256];
1818 assert_eq!(r.log_iter_rev(&mut buf)?.expect("log exists").count(), 1);
1919 Ok(())
@@ -21,11 +21,9 @@ mod reflog { · 1 unmodified line
2121 }
2222
2323 mod peel {
24− use crate::file;
25− use crate::file::store_with_packed_refs;
24+ use crate::{file, file::store_with_packed_refs};
2625 use git_testtools::hex_to_id;
2726 use std::convert::TryFrom;
28− use std::path::Path;
2927
3028 #[test]
3129 fn one_level() -> crate::Result {
@@ -36,12 +34,12 @@ mod peel { · 4 unmodified lines
3634 let nr = git_ref::file::Reference::try_from(r.peel_one_level(None).expect("exists").expect("no failure"))
3735 .expect("loose ref");
3836 assert!(
39− matches!(nr.target(), git_ref::Target::Peeled(_)),
37+ matches!(nr.target.borrow(), git_ref::Target::Peeled(_)),
4038 "iteration peels a single level"
4139 );
4240 assert!(nr.peel_one_level(None).is_none(), "end of iteration");
4341 assert_eq!(
44− nr.target(),
42+ nr.target.borrow(),
4543 git_ref::Target::Peeled(&hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03")),
4644 "we still have the peeled target"
4745 );
@@ -69,7 +67,7 @@ mod peel { · 21 unmodified lines
6967 r.peel_to_id_in_place(None)?,
7068 hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03")
7169 );
72− assert_eq!(r.relative_path(), Path::new("refs/remotes/origin/multi-link-target3"));
70+ assert_eq!(r.name.as_ref(), "refs/remotes/origin/multi-link-target3");
7371
7472 Ok(())
7573 }
@@ -79,17 +77,13 @@ mod peel { · 3 unmodified lines
7977 let store = file::store()?;
8078 let mut r = store.loose_find_existing("loop-a")?;
8179 assert_eq!(r.kind(), git_ref::Kind::Symbolic, "there is something to peel");
82− assert_eq!(r.relative_path(), Path::new("refs/loop-a"));
80+ assert_eq!(r.name.as_ref(), "refs/loop-a");
8381
8482 assert!(matches!(
8583 r.peel_to_id_in_place(None).unwrap_err(),
8684 git_ref::file::reference::peel::to_id::Error::Cycle { .. }
8785 ));
88− assert_eq!(
89− r.relative_path(),
90− Path::new("refs/loop-a"),
91− "the ref is not changed on error"
92− );
86+ assert_eq!(r.name.as_ref(), "refs/loop-a", "the ref is not changed on error");
9387 Ok(())
9488 }
9589 }
@@ -109,8 +103,14 @@ mod parse { · 13 unmodified lines
109103 ($name:ident, $input:literal, $err:literal) => {
110104 #[test]
111105 fn $name() {
106+ use std::convert::TryInto;
112107 let store = store();
113− let err = Reference::try_from_path(&store, "name", $input).unwrap_err();
108+ let err = Reference::try_from_path(
109+ &store,
110+ "HEAD".try_into().expect("this is a valid name"),
111+ $input,
112+ )
113+ .unwrap_err();
114114 assert_eq!(err.to_string(), $err);
115115 }
116116 };
@@ -129,11 +129,17 @@ mod parse { · 12 unmodified lines
129129 ($name:ident, $input:literal, $kind:path, $id:expr, $ref:expr) => {
130130 #[test]
131131 fn $name() {
132+ use std::convert::TryInto;
132133 let store = store();
133− let reference = Reference::try_from_path(&store, "name", $input).unwrap();
134+ let reference = Reference::try_from_path(
135+ &store,
136+ "HEAD".try_into().expect("valid static name"),
137+ $input,
138+ )
139+ .unwrap();
134140 assert_eq!(reference.kind(), $kind);
135− assert_eq!(reference.target().as_id(), $id);
136− assert_eq!(reference.target().as_name(), $ref);
141+ assert_eq!(reference.target.borrow().as_id(), $id);
142+ assert_eq!(reference.target.borrow().as_name(), $ref);
137143 }
138144 };
139145 }
git-ref/tests/file/store/find.rs+4−5
@@ -1,6 +1,5 @@
11 use crate::file::{store, store_at};
22 use git_testtools::hex_to_id;
3−use std::path::Path;
43
54 mod existing {
65 use crate::file::store;
@@ -12,7 +11,7 @@ mod existing { · 5 unmodified lines
1211 for (partial_name, expected_path) in &[("main", Some("refs/heads/main")), ("does-not-exist", None)] {
1312 let reference = store.loose_find_existing(*partial_name);
1413 match expected_path {
15− Some(expected_path) => assert_eq!(reference?.relative_path(), Path::new(expected_path)),
14+ Some(expected_path) => assert_eq!(reference?.name.as_ref(), expected_path),
1615 None => match reference {
1716 Ok(_) => panic!("Expected error"),
1817 Err(git_ref::file::find::existing::Error::NotFound(name)) => {
@@ -33,7 +32,7 @@ fn with_packed_refs() -> crate::Result { · 14 unmodified lines
3332 let packed = store.packed()?;
3433 let r = store.find_existing("main", packed.as_ref())?;
3534 assert_eq!(r.target().borrow().as_id().expect("peeled"), c1);
36− assert_eq!(r.name().expect("valid name").as_ref(), "refs/heads/main");
35+ assert_eq!(r.name().expect("valid name").as_bstr(), "refs/heads/main");
3736 Ok(())
3837 }
3938
@@ -55,8 +54,8 @@ fn success() -> crate::Result { · 15 unmodified lines
5554 ("refs/heads/main", "refs/heads/main", git_ref::Kind::Peeled),
5655 ] {
5756 let reference = store.loose_find(*partial_name)?.expect("exists");
58− assert_eq!(reference.relative_path(), Path::new(expected_path));
59− assert_eq!(reference.target().kind(), *expected_ref_kind);
57+ assert_eq!(reference.name.as_bstr(), expected_path);
58+ assert_eq!(reference.target.borrow().kind(), *expected_ref_kind);
6059 }
6160 Ok(())
6261 }
git-ref/tests/file/store/iter.rs+7−7
@@ -1,7 +1,7 @@
11 use crate::file::{store, store_at, store_with_packed_refs};
22 use bstr::ByteSlice;
33 use git_testtools::hex_to_id;
4−use std::{convert::TryInto, path::PathBuf};
4+use std::convert::TryInto;
55
66 #[test]
77 fn no_packed_available_thus_no_iteration_possible() -> crate::Result {
@@ -47,7 +47,7 @@ fn loose_iter_with_broken_refs() -> crate::Result { · 39 unmodified lines
4747 );
4848 let ref_paths: Vec<_> = actual
4949 .drain(..first_error)
50− .filter_map(|e| e.ok().map(|e| e.into_relative_path()))
50+ .filter_map(|e| e.ok().map(|e| e.name.into_inner()))
5151 .collect();
5252
5353 assert_eq!(
@@ -69,7 +69,7 @@ fn loose_iter_with_broken_refs() -> crate::Result { · 15 unmodified lines
6969 "tags/t1"
7070 ]
7171 .into_iter()
72− .map(|p| PathBuf::from(format!("refs/{}", p)))
72+ .map(|p| format!("refs/{}", p))
7373 .collect::<Vec<_>>(),
7474 "all paths are as expected"
7575 );
@@ -100,7 +100,7 @@ fn loose_iter_with_prefix() -> crate::Result { · 24 unmodified lines
100100 .collect::<Result<Vec<_>, _>>()
101101 .expect("no broken ref in this subset")
102102 .into_iter()
103− .map(|e| e.into_relative_path())
103+ .map(|e| e.name.into_inner())
104104 .collect::<Vec<_>>();
105105
106106 assert_eq!(
@@ -112,7 +112,7 @@ fn loose_iter_with_prefix() -> crate::Result { · 5 unmodified lines
112112 "refs/heads/multi-link-target1",
113113 ]
114114 .into_iter()
115− .map(PathBuf::from)
115+ .map(String::from)
116116 .collect::<Vec<_>>(),
117117 "all paths are as expected"
118118 );
@@ -129,7 +129,7 @@ fn overlay_iter() -> crate::Result { · 10 unmodified lines
129129 .map(|r| {
130130 r.map(|r| {
131131 (
132− r.name().expect("valid names only").into_inner(),
132+ r.name().expect("valid names only").as_bstr().to_owned(),
133133 r.target(),
134134 r.is_packed(),
135135 )
@@ -185,7 +185,7 @@ fn overlay_prefixed_iter() -> crate::Result { · 49 unmodified lines
185185 .map(|r| {
186186 r.map(|r| {
187187 (
188− r.name().expect("valid names only").into_inner(),
188+ r.name().expect("valid names only").as_bstr().to_owned(),
189189 r.target(),
190190 r.is_packed(),
191191 )
git-ref/tests/file/transaction/prepare_and_commit/create_or_update.rs+15−15
@@ -11,7 +11,7 @@ use git_ref::{ · 10 unmodified lines
1111 transaction::{Change, Create, LogChange, RefEdit, RefLog},
1212 };
1313 use git_testtools::hex_to_id;
14−use std::{convert::TryInto, path::Path};
14+use std::convert::TryInto;
1515
1616 mod reference_with_equally_named {
1717 use crate::file::transaction::prepare_and_commit::{committer, empty_store};
@@ -50,7 +50,7 @@ mod reference_with_equally_named { · 32 unmodified lines
5050 if *is_empty {
5151 let edits = edits?;
5252 assert!(
53− store.find(edits[0].name.to_partial(), None)?.is_some(),
53+ store.loose_find(edits[0].name.to_partial())?.is_some(),
5454 "HEAD was created despite a directory being in the way"
5555 );
5656 } else {
@@ -108,8 +108,8 @@ fn reference_with_old_value_must_exist_when_creating_it() -> crate::Result { · 51 unmodified lines
108108 #[test]
109109 fn reference_with_explicit_value_must_match_the_value_on_update() -> crate::Result {
110110 let (_keep, store) = store_writable("make_repo_for_reflog.sh")?;
111− let head = store.find("HEAD", None)?.expect("head exists already");
112− let target = head.target().to_owned();
111+ let head = store.loose_find("HEAD")?.expect("head exists already");
112+ let target = head.target;
113113
114114 let err = store
115115 .transaction(
@@ -144,8 +144,8 @@ fn reference_with_explicit_value_must_match_the_value_on_update() -> crate::Resu · 28 unmodified lines
144144 #[test]
145145 fn reference_with_create_only_must_not_exist_already_when_creating_it_if_the_value_does_not_match() -> crate::Result {
146146 let (_keep, store) = store_writable("make_repo_for_reflog.sh")?;
147− let head = store.find("HEAD", None)?.expect("head exists already");
148− let target = head.target().to_owned();
147+ let head = store.loose_find("HEAD")?.expect("head exists already");
148+ let target = head.target;
149149
150150 let err = store
151151 .transaction(
@@ -178,8 +178,8 @@ fn reference_with_create_only_must_not_exist_already_when_creating_it_if_the_val · 26 unmodified lines
178178 #[test]
179179 fn reference_with_create_only_must_not_exist_already_when_creating_it_unless_the_value_matches() -> crate::Result {
180180 let (_keep, store) = store_writable("make_repo_for_reflog.sh")?;
181− let head = store.find("HEAD", None)?.expect("head exists already");
182− let target = head.target().to_owned();
181+ let head = store.loose_find("HEAD")?.expect("head exists already");
182+ let target = head.target;
183183 let previous_reflog_count = reflog_lines(&store, "HEAD")?.len();
184184
185185 let edits = store
@@ -258,7 +258,7 @@ fn symbolic_head_missing_referent_then_update_referent() -> crate::Result { · 72 unmodified lines
258258 let (_keep, mut store) = empty_store()?;
259259 store.write_reflog = *reflog_writemode;
260260 let referent = "refs/heads/alt-main";
261− assert!(store.find(referent, None)?.is_none(), "the reference does not exist");
261+ assert!(store.loose_find(referent)?.is_none(), "the reference does not exist");
262262 let log_ignored = LogChange {
263263 mode: RefLog::AndReference,
264264 force_create_reflog: false,
@@ -294,11 +294,11 @@ fn symbolic_head_missing_referent_then_update_referent() -> crate::Result { · 29 unmodified lines
294294 );
295295
296296 let head = store.loose_find_existing(edits[0].name.to_partial())?;
297− assert_eq!(head.relative_path(), Path::new("HEAD"));
297+ assert_eq!(head.name.as_bstr(), "HEAD");
298298 assert_eq!(head.kind(), git_ref::Kind::Symbolic);
299− assert_eq!(head.target().as_name(), Some(referent.as_bytes().as_bstr()));
299+ assert_eq!(head.target.borrow().as_name(), Some(referent.as_bytes().as_bstr()));
300300 assert!(!head.log_exists()?, "no reflog is written for symbolic ref");
301− assert!(store.find(referent, None)?.is_none(), "referent wasn't created");
301+ assert!(store.loose_find(referent)?.is_none(), "referent wasn't created");
302302
303303 let new_oid = hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242");
304304 let new = Target::Peeled(new_oid);
@@ -360,7 +360,7 @@ fn symbolic_head_missing_referent_then_update_referent() -> crate::Result { · 55 unmodified lines
360360 "head is still symbolic, not detached"
361361 );
362362 assert_eq!(
363− head.target().as_name(),
363+ head.target.borrow().as_name(),
364364 Some(referent.as_bytes().as_bstr()),
365365 "it still points to the referent"
366366 );
@@ -368,7 +368,7 @@ fn symbolic_head_missing_referent_then_update_referent() -> crate::Result { · 1 unmodified line
368368 let referent_ref = store.loose_find_existing(referent)?;
369369 assert_eq!(referent_ref.kind(), git_ref::Kind::Peeled, "referent is a peeled ref");
370370 assert_eq!(
371− referent_ref.target().as_id(),
371+ referent_ref.target.borrow().as_id(),
372372 Some(new_oid.as_ref()),
373373 "referent points to desired hash"
374374 );
@@ -398,7 +398,7 @@ fn symbolic_head_missing_referent_then_update_referent() -> crate::Result { · 23 unmodified lines
398398 fn write_reference_to_which_head_points_to_does_not_update_heads_reflog_even_though_it_should() -> crate::Result {
399399 let (_keep, store) = store_writable("make_repo_for_reflog.sh")?;
400400 let head = store.loose_find_existing("HEAD")?;
401− let referent = head.target().as_name().expect("symbolic ref").to_owned();
401+ let referent = head.target.borrow().as_name().expect("symbolic ref").to_owned();
402402 let previous_head_reflog = reflog_lines(&store, "HEAD")?;
403403
404404 let new_id = hex_to_id("01dd4e2a978a9f5bd773dae6da7aa4a5ac1cdbbc");
git-ref/tests/file/transaction/prepare_and_commit/delete.rs+20−20
@@ -67,7 +67,7 @@ fn delete_ref_and_reflog_on_symbolic_no_deref() -> crate::Result { · 66 unmodified lines
6767 previous: Some(Target::must_exist()),
6868 log: RefLog::AndReference,
6969 },
70− name: head.name().into(),
70+ name: head.name.clone(),
7171 deref: false,
7272 }),
7373 Fail::Immediately,
@@ -81,7 +81,7 @@ fn delete_ref_and_reflog_on_symbolic_no_deref() -> crate::Result { · 7 unmodified lines
8181 previous: Some(Target::Symbolic("refs/heads/main".try_into()?)),
8282 log: RefLog::AndReference,
8383 },
84− name: head.name().into(),
84+ name: head.name,
8585 deref: false
8686 }],
8787 "the previous value was updated with the actual one"
@@ -90,8 +90,8 @@ fn delete_ref_and_reflog_on_symbolic_no_deref() -> crate::Result { · 2 unmodified lines
9090 store.reflog_iter_rev("HEAD", &mut [0u8; 128])?.is_none(),
9191 "reflog was deleted"
9292 );
93− assert!(store.find("HEAD", None)?.is_none(), "ref was deleted");
94− assert!(store.find("main", None)?.is_some(), "referent still exists");
93+ assert!(store.loose_find("HEAD")?.is_none(), "ref was deleted");
94+ assert!(store.loose_find("main")?.is_some(), "referent still exists");
9595 Ok(())
9696 }
9797
@@ -108,7 +108,7 @@ fn delete_ref_with_incorrect_previous_value_fails() { · 10 unmodified lines
108108 previous: Some(Target::Symbolic("refs/heads/main".try_into().unwrap())),
109109 log: RefLog::Only,
110110 },
111− name: head.name().into(),
111+ name: head.name.clone(),
112112 deref: true,
113113 }),
114114 Fail::Immediately,
@@ -118,9 +118,9 @@ fn delete_ref_with_incorrect_previous_value_fails() { · 3 unmodified lines
118118
119119 assert_eq!(err.to_string(), "The reference 'refs/heads/main' should have content ref: refs/heads/main, actual content was 02a7a22d90d7c02fb494ed25551850b868e634f0");
120120 // everything stays as is
121− let head = store.find_existing("HEAD", None).unwrap();
121+ let head = store.loose_find_existing("HEAD").unwrap();
122122 assert!(head.log_exists().unwrap());
123− let main = store.find_existing("main", None).expect("referent still exists");
123+ let main = store.loose_find_existing("main").expect("referent still exists");
124124 assert!(main.log_exists().unwrap());
125125 }
126126
@@ -137,7 +137,7 @@ fn delete_reflog_only_of_symbolic_no_deref() -> crate::Result { · 10 unmodified lines
137137 previous: Some(Target::Symbolic("refs/heads/main".try_into()?)),
138138 log: RefLog::Only,
139139 },
140− name: head.name().into(),
140+ name: head.name,
141141 deref: false,
142142 }),
143143 Fail::Immediately,
@@ -145,12 +145,12 @@ fn delete_reflog_only_of_symbolic_no_deref() -> crate::Result { · 1 unmodified line
145145 .commit(&committer())?;
146146
147147 assert_eq!(edits.len(), 1);
148− let head = store.find_existing("HEAD", None)?;
148+ let head = store.loose_find_existing("HEAD")?;
149149 assert!(!head.log_exists().unwrap());
150− let main = store.find_existing("main", None).expect("referent still exists");
150+ let main = store.loose_find_existing("main").expect("referent still exists");
151151 assert!(main.log_exists()?, "log is untouched, too");
152152 assert_eq!(
153− main.target(),
153+ main.target,
154154 head.peel_one_level(None).expect("a symref")?.target(),
155155 "head points to main"
156156 );
@@ -170,7 +170,7 @@ fn delete_reflog_only_of_symbolic_with_deref() -> crate::Result { · 13 unmodified lines
170170 previous: Some(Target::must_exist()),
171171 log: RefLog::Only,
172172 },
173− name: head.name().into(),
173+ name: head.name,
174174 deref: true,
175175 }),
176176 Fail::Immediately,
@@ -178,12 +178,12 @@ fn delete_reflog_only_of_symbolic_with_deref() -> crate::Result { · 1 unmodified line
178178 .commit(&committer())?;
179179
180180 assert_eq!(edits.len(), 2);
181− let head = store.find_existing("HEAD", None)?;
181+ let head = store.loose_find_existing("HEAD")?;
182182 assert!(!head.log_exists()?);
183− let main = store.find_existing("main", None).expect("referent still exists");
183+ let main = store.loose_find_existing("main").expect("referent still exists");
184184 assert!(!main.log_exists()?, "log is removed");
185185 assert_eq!(
186− main.target(),
186+ main.target,
187187 head.peel_one_level(None).expect("a symref")?.target(),
188188 "head points to main"
189189 );
@@ -195,7 +195,7 @@ fn delete_reflog_only_of_symbolic_with_deref() -> crate::Result { · 5 unmodified lines
195195 fn delete_broken_ref_that_must_exist_fails_as_it_is_no_valid_ref() {
196196 let (_keep, store) = empty_store().unwrap();
197197 std::fs::write(store.base.join("HEAD"), &b"broken").unwrap();
198− assert!(store.find("HEAD", None).is_err(), "the ref is truly broken");
198+ assert!(store.loose_find("HEAD").is_err(), "the ref is truly broken");
199199
200200 let err = store
201201 .transaction(
@@ -222,7 +222,7 @@ fn delete_broken_ref_that_must_exist_fails_as_it_is_no_valid_ref() { · 20 unmodified lines
222222 fn delete_broken_ref_that_may_not_exist_works_even_in_deref_mode() -> crate::Result {
223223 let (_keep, store) = empty_store()?;
224224 std::fs::write(store.base.join("HEAD"), &b"broken")?;
225− assert!(store.find("HEAD", None).is_err(), "the ref is truly broken");
225+ assert!(store.loose_find("HEAD").is_err(), "the ref is truly broken");
226226
227227 let edits = store
228228 .transaction(
@@ -238,7 +238,7 @@ fn delete_broken_ref_that_may_not_exist_works_even_in_deref_mode() -> crate::Res · 9 unmodified lines
238238 )
239239 .commit(&committer())?;
240240
241− assert!(store.find("HEAD", None)?.is_none(), "the ref was deleted");
241+ assert!(store.loose_find("HEAD")?.is_none(), "the ref was deleted");
242242 assert_eq!(
243243 edits,
244244 vec![RefEdit {
@@ -258,7 +258,7 @@ fn store_write_mode_has_no_effect_and_reflogs_are_always_deleted() -> crate::Res · 13 unmodified lines
258258 for reflog_writemode in &[git_ref::file::WriteReflog::Normal, git_ref::file::WriteReflog::Disable] {
259259 let (_keep, mut store) = store_writable("make_repo_for_reflog.sh")?;
260260 store.write_reflog = *reflog_writemode;
261− assert!(store.find_existing("HEAD", None)?.log_exists()?,);
261+ assert!(store.loose_find_existing("HEAD")?.log_exists()?,);
262262 let edits = store
263263 .transaction(
264264 Some(RefEdit {
@@ -273,7 +273,7 @@ fn store_write_mode_has_no_effect_and_reflogs_are_always_deleted() -> crate::Res · 8 unmodified lines
273273 )
274274 .commit(&committer())?;
275275 assert_eq!(edits.len(), 1);
276− assert!(!store.find_existing("HEAD", None)?.log_exists()?, "log was deleted");
276+ assert!(!store.loose_find_existing("HEAD")?.log_exists()?, "log was deleted");
277277 }
278278 Ok(())
279279 }
git-ref/tests/packed/find.rs+5−5
@@ -3,7 +3,7 @@ use crate::{ · 2 unmodified lines
33 packed::write_packed_refs_with,
44 };
55 use git_ref::{packed, PartialName};
6−use std::{convert::TryFrom, path::Path};
6+use std::convert::TryFrom;
77
88 #[test]
99 fn a_lock_file_would_not_be_a_valid_partial_name() {
@@ -73,8 +73,8 @@ fn partial_name_to_full_name_conversion_rules_are_applied() -> crate::Result { · 63 unmodified lines
7373 let packed = store.packed()?.expect("packed-refs exists");
7474
7575 assert_eq!(
76− store.loose_find_existing("origin")?.relative_path(),
77− Path::new("refs/remotes/origin/HEAD"),
76+ store.loose_find_existing("origin")?.name.as_bstr(),
77+ "refs/remotes/origin/HEAD",
7878 "a special that only applies to loose refs"
7979 );
8080 assert!(
@@ -82,8 +82,8 @@ fn partial_name_to_full_name_conversion_rules_are_applied() -> crate::Result { · 1 unmodified line
8282 "packed refs don't have this special case as they don't store HEADs or symrefs"
8383 );
8484 assert_eq!(
85− store.loose_find_existing("HEAD")?.relative_path(),
86− Path::new("HEAD"),
85+ store.loose_find_existing("HEAD")?.name.as_bstr(),
86+ "HEAD",
8787 "HEAD can be found in loose stores"
8888 );
8989 assert!(
git-repository/src/path/is_git.rs+4−4
@@ -9,8 +9,8 @@ quick_error! { · 8 unmodified lines
99 from()
1010 source(err)
1111 }
12− MisplacedHead(relative_path: PathBuf) {
13− display("Expected HEAD at '.git/HEAD', got '.git/{}'", relative_path.display())
12+ MisplacedHead(name: crate::object::bstr::BString) {
13+ display("Expected HEAD at '.git/HEAD', got '.git/{}'", name)
1414 }
1515 MissingObjectsDirectory(missing: PathBuf) {
1616 display("Expected an objects directory at '{}'", missing.display())
@@ -42,8 +42,8 @@ pub fn is_git(git_dir: impl AsRef<Path>) -> Result<crate::Kind, Error> { · 25 unmodified lines
4242 {
4343 let refs = git_ref::file::Store::at(&dot_git, Default::default());
4444 let head = refs.loose_find_existing("HEAD")?;
45− if head.relative_path() != Path::new("HEAD") {
46− return Err(Error::MisplacedHead(head.into_relative_path()));
45+ if head.name().as_bstr() != "HEAD" {
46+ return Err(Error::MisplacedHead(head.into_name().into_inner()));
4747 }
4848 }
4949

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t