Previously it would be parsed, but always error as the implementation didn't exist. Now it will return the fetch and push tracking branches respectively.
Unified · Split
| @@ -199,10 +199,9 @@ impl<'repo> Delegate<'repo> { · 198 unmodified lines | ||
| 199 | 199 | } |
| 200 | 200 | } |
| 201 | 201 | fn follow_refs_to_objects_if_needed(&mut self) -> Option<()> { |
| 202 | − assert_eq!(self.refs.len(), self.objs.len()); | |
| 203 | 202 | let repo = self.repo; |
| 204 | 203 | for (r, obj) in self.refs.iter().zip(self.objs.iter_mut()) { |
| 205 | − if let (_ref_opt @ Some(ref_), obj_opt @ None) = (r, obj) { | |
| 204 | + if let (Some(ref_), obj_opt @ None) = (r, obj) { | |
| 206 | 205 | if let Some(id) = ref_.target.try_id().map(ToOwned::to_owned).or_else(|| { |
| 207 | 206 | ref_.clone() |
| 208 | 207 | .attach(repo) |
| @@ -9,6 +9,7 @@ use gix_revision::spec::parse::{ · 8 unmodified lines | ||
| 9 | 9 | use crate::{ |
| 10 | 10 | bstr::{BStr, BString, ByteSlice}, |
| 11 | 11 | ext::ReferenceExt, |
| 12 | + remote, | |
| 12 | 13 | revision::spec::parse::{Delegate, Error, RefsHint}, |
| 13 | 14 | }; |
| 14 | 15 | |
| @@ -106,6 +107,7 @@ impl<'repo> delegate::Revision for Delegate<'repo> { · 91 unmodified lines | ||
| 106 | 107 | self.unset_disambiguate_call(); |
| 107 | 108 | match query { |
| 108 | 109 | ReflogLookup::Date(_date) => { |
| 110 | + // TODO: actually do this - this should be possible now despite incomplete date parsing | |
| 109 | 111 | self.err.push(Error::Planned { |
| 110 | 112 | dependency: "remote handling and ref-specs are fleshed out more", |
| 111 | 113 | }); |
| @@ -215,11 +217,51 @@ impl<'repo> delegate::Revision for Delegate<'repo> { · 103 unmodified lines | ||
| 215 | 217 | } |
| 216 | 218 | } |
| 217 | 219 | |
| 218 | − fn sibling_branch(&mut self, _kind: SiblingBranch) -> Option<()> { | |
| 220 | + fn sibling_branch(&mut self, kind: SiblingBranch) -> Option<()> { | |
| 219 | 221 | self.unset_disambiguate_call(); |
| 220 | − self.err.push(Error::Planned { | |
| 221 | − dependency: "remote handling and ref-specs are fleshed out more", | |
| 222 | − }); | |
| 222 | + let reference = match &mut self.refs[self.idx] { | |
| 223 | + val @ None => match self.repo.head().map(crate::Head::try_into_referent) { | |
| 224 | + Ok(Some(r)) => { | |
| 225 | + *val = Some(r.clone().detach()); | |
| 226 | + r | |
| 227 | + } | |
| 228 | + Ok(None) => { | |
| 229 | + self.err.push(Error::UnbornHeadForSibling); | |
| 230 | + return None; | |
| 231 | + } | |
| 232 | + Err(err) => { | |
| 233 | + self.err.push(err.into()); | |
| 234 | + return None; | |
| 235 | + } | |
| 236 | + }, | |
| 237 | + Some(r) => r.clone().attach(self.repo), | |
| 238 | + }; | |
| 239 | + let direction = match kind { | |
| 240 | + SiblingBranch::Upstream => remote::Direction::Fetch, | |
| 241 | + SiblingBranch::Push => remote::Direction::Push, | |
| 242 | + }; | |
| 243 | + match reference.remote_tracking_ref_name(direction) { | |
| 244 | + None => self.err.push(Error::NoTrackingBranch { | |
| 245 | + name: reference.inner.name, | |
| 246 | + direction, | |
| 247 | + }), | |
| 248 | + Some(Err(err)) => self.err.push(Error::GetTrackingBranch { | |
| 249 | + name: reference.inner.name, | |
| 250 | + direction, | |
| 251 | + source: Box::new(err), | |
| 252 | + }), | |
| 253 | + Some(Ok(name)) => match self.repo.find_reference(name.as_ref()) { | |
| 254 | + Err(err) => self.err.push(Error::GetTrackingBranch { | |
| 255 | + name: reference.inner.name, | |
| 256 | + direction, | |
| 257 | + source: Box::new(err), | |
| 258 | + }), | |
| 259 | + Ok(r) => { | |
| 260 | + self.refs[self.idx] = r.inner.into(); | |
| 261 | + return Some(()); | |
| 262 | + } | |
| 263 | + }, | |
| 264 | + }; | |
| 223 | 265 | None |
| 224 | 266 | } |
| 225 | 267 | } |
| @@ -1,4 +1,4 @@ | ||
| 1 | −use crate::{bstr::BString, object, reference}; | |
| 1 | +use crate::{bstr::BString, object, reference, remote}; | |
| 2 | 2 | |
| 3 | 3 | /// A hint to know what to do if refs and object names are equal. |
| 4 | 4 | #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] |
| @@ -59,6 +59,19 @@ pub enum Error { · 54 unmodified lines | ||
| 59 | 59 | Malformed, |
| 60 | 60 | #[error("Unborn heads do not have a reflog yet")] |
| 61 | 61 | UnbornHeadsHaveNoRefLog, |
| 62 | + #[error("Unborn heads cannot have push or upstream tracking branches")] | |
| 63 | + UnbornHeadForSibling, | |
| 64 | + #[error("Branch named {name} does not have a {} tracking branch configured", direction.as_str())] | |
| 65 | + NoTrackingBranch { | |
| 66 | + name: gix_ref::FullName, | |
| 67 | + direction: remote::Direction, | |
| 68 | + }, | |
| 69 | + #[error("Error when obtaining {} tracking branch for {name}", direction.as_str())] | |
| 70 | + GetTrackingBranch { | |
| 71 | + name: gix_ref::FullName, | |
| 72 | + direction: remote::Direction, | |
| 73 | + source: Box<dyn std::error::Error + Send + Sync + 'static>, | |
| 74 | + }, | |
| 62 | 75 | #[error("This feature will be implemented once {dependency}")] |
| 63 | 76 | Planned { dependency: &'static str }, |
| 64 | 77 | #[error("Reference {reference:?} does not have a reference log, cannot {action}")] |
Binary file not shown.
| @@ -338,6 +338,16 @@ git init complex_graph · 337 unmodified lines | ||
| 338 | 338 | git add file && git commit -m A |
| 339 | 339 | git branch a |
| 340 | 340 | |
| 341 | + git remote add origin . | |
| 342 | + cat <<EOF>>.git/config | |
| 343 | + | |
| 344 | + [branch "main"] | |
| 345 | + remote = origin | |
| 346 | + merge = refs/heads/main | |
| 347 | +EOF | |
| 348 | + | |
| 349 | + git fetch | |
| 350 | + | |
| 341 | 351 | baseline ":/message" # finds 'message recent' instead of 'initial message' |
| 342 | 352 | baseline ":/!-message" # above, negated |
| 343 | 353 | baseline ":/mes.age" # regexes work too |
| @@ -391,6 +401,11 @@ git init complex_graph · 47 unmodified lines | ||
| 391 | 401 | baseline "@:" |
| 392 | 402 | baseline "4b825dc642cb6eb9a060e54bf8d69288fbee4904" |
| 393 | 403 | |
| 404 | + baseline @{push} | |
| 405 | + baseline main@{push} | |
| 406 | + baseline main@{upstream} | |
| 407 | + baseline @{upstream} | |
| 408 | + | |
| 394 | 409 | baseline "^" |
| 395 | 410 | baseline "^!" |
| 396 | 411 | baseline "..." |
| @@ -13,22 +13,27 @@ mod traverse; · 12 unmodified lines | ||
| 13 | 13 | mod peel; |
| 14 | 14 | |
| 15 | 15 | mod sibling_branch { |
| 16 | − use gix::revision::spec::parse::Error; | |
| 17 | − | |
| 18 | − use crate::revision::spec::from_bytes::{parse_spec_no_baseline, repo}; | |
| 16 | + use crate::revision::spec::from_bytes::{parse_spec, repo}; | |
| 17 | + use crate::util::hex_to_id; | |
| 19 | 18 | |
| 20 | 19 | #[test] |
| 21 | − fn is_planned_and_delayed_until_remotes_are_sorted() { | |
| 20 | + fn push_and_upstream() -> crate::Result { | |
| 22 | 21 | let repo = repo("complex_graph").unwrap(); |
| 23 | − assert!(matches!( | |
| 24 | − parse_spec_no_baseline("main@{push}", &repo).unwrap_err(), | |
| 25 | − Error::Planned { .. } | |
| 26 | − )); | |
| 27 | − | |
| 28 | − assert!(matches!( | |
| 29 | − parse_spec_no_baseline("main@{upstream}", &repo).unwrap_err(), | |
| 30 | − Error::Planned { .. } | |
| 31 | − )); | |
| 22 | + for op in ["upstream", "push"] { | |
| 23 | + for branch in ["", "main"] { | |
| 24 | + let actual = parse_spec(format!("{branch}@{{{op}}}"), &repo)?; | |
| 25 | + assert_eq!( | |
| 26 | + actual.first_reference().expect("set").name.as_bstr(), | |
| 27 | + "refs/remotes/origin/main" | |
| 28 | + ); | |
| 29 | + assert_eq!(actual.second_reference(), None); | |
| 30 | + assert_eq!( | |
| 31 | + actual.single().expect("just one"), | |
| 32 | + hex_to_id("55e825ebe8fd2ff78cad3826afb696b96b576a7e") | |
| 33 | + ); | |
| 34 | + } | |
| 35 | + } | |
| 36 | + Ok(()) | |
| 32 | 37 | } |
| 33 | 38 | } |
| 34 | 39 | |
| @@ -189,11 +189,11 @@ fn compare_with_baseline( · 188 unmodified lines | ||
| 189 | 189 | } |
| 190 | 190 | } |
| 191 | 191 | |
| 192 | −pub fn parse_spec<'a>( | |
| 193 | − spec: &str, | |
| 194 | − repo: &'a gix::Repository, | |
| 195 | −) -> Result<gix::revision::Spec<'a>, gix::revision::spec::parse::Error> { | |
| 196 | − parse_spec_opts(spec, repo, Default::default()) | |
| 192 | +pub fn parse_spec( | |
| 193 | + spec: impl AsRef<str>, | |
| 194 | + repo: &gix::Repository, | |
| 195 | +) -> Result<gix::revision::Spec<'_>, gix::revision::spec::parse::Error> { | |
| 196 | + parse_spec_opts(spec.as_ref(), repo, Default::default()) | |
| 197 | 197 | } |
| 198 | 198 | |
| 199 | 199 | pub fn repo(name: &str) -> crate::Result<gix::Repository> { |