Struct git_repository::Id

source ·
pub struct Id<'r> { /* private fields */ }
Expand description

An ObjectId with access to a repository.

Implementations§

An object id infused with Easy.

Find the Object associated with this object id, and consider it an error if it doesn’t exist.

Note

There can only be one ObjectRef per Easy. To increase that limit, clone the Easy.

Examples found in repository?
src/object/tree/mod.rs (line 136)
135
136
137
        pub fn object(&self) -> Result<crate::Object<'repo>, crate::object::find::existing::Error> {
            self.id().object()
        }
More examples
Hide additional examples
src/object/commit.rs (line 114)
113
114
115
116
117
118
    pub fn tree(&self) -> Result<Tree<'repo>, Error> {
        match self.tree_id()?.object()?.try_into_tree() {
            Ok(tree) => Ok(tree),
            Err(crate::object::try_into::Error { actual, expected, .. }) => Err(Error::ObjectKind { actual, expected }),
        }
    }
src/object/blob.rs (line 41)
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
        pub fn from_ids(
            previous_id: &crate::Id<'old>,
            new_id: &crate::Id<'new>,
        ) -> Result<Platform<'old, 'new>, init::Error> {
            match previous_id
                .object()
                .and_then(|old| new_id.object().map(|new| (old, new)))
            {
                Ok((old, new)) => {
                    let algo = match new_id.repo.config.diff_algorithm() {
                        Ok(algo) => algo,
                        Err(err) => return Err(err.into()),
                    };
                    Ok(Platform { old, new, algo })
                }
                Err(err) => Err(err.into()),
            }
        }
src/head/peel.rs (line 63)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    pub fn peel_to_id_in_place(&mut self) -> Option<Result<crate::Id<'repo>, Error>> {
        Some(match &mut self.kind {
            Kind::Unborn(_name) => return None,
            Kind::Detached {
                peeled: Some(peeled), ..
            } => Ok((*peeled).attach(self.repo)),
            Kind::Detached { peeled: None, target } => {
                match target
                    .attach(self.repo)
                    .object()
                    .map_err(Into::into)
                    .and_then(|obj| obj.peel_tags_to_end().map_err(Into::into))
                    .map(|peeled| peeled.id)
                {
                    Ok(peeled) => {
                        self.kind = Kind::Detached {
                            peeled: Some(peeled),
                            target: *target,
                        };
                        Ok(peeled.attach(self.repo))
                    }
                    Err(err) => Err(err),
                }
            }
            Kind::Symbolic(r) => {
                let mut nr = r.clone().attach(self.repo);
                let peeled = nr.peel_to_id_in_place().map_err(Into::into);
                *r = nr.detach();
                peeled
            }
        })
    }

    // TODO: tests
    // TODO: something similar in `crate::Reference`
    /// Follow the symbolic reference of this head until its target object and peel it by following tag objects until there is no
    /// more object to follow, transform the id into a commit if possible and return that.
    ///
    /// Returns an error if the head is unborn or if it doesn't point to a commit.
    pub fn peel_to_commit_in_place(&mut self) -> Result<crate::Commit<'repo>, to_commit::Error> {
        let id = self.peel_to_id_in_place().ok_or_else(|| to_commit::Error::Unborn {
            name: self.referent_name().expect("unborn").to_owned(),
        })??;
        id.object()
            .map_err(|err| to_commit::Error::Peel(Error::FindExistingObject(err)))
            .and_then(|object| object.try_into_commit().map_err(Into::into))
    }

    /// Consume this instance and transform it into the final object that it points to, or `None` if the `HEAD`
    /// reference is yet to be born.
    pub fn into_fully_peeled_id(self) -> Option<Result<crate::Id<'repo>, Error>> {
        Some(match self.kind {
            Kind::Unborn(_name) => return None,
            Kind::Detached {
                peeled: Some(peeled), ..
            } => Ok(peeled.attach(self.repo)),
            Kind::Detached { peeled: None, target } => target
                .attach(self.repo)
                .object()
                .map_err(Into::into)
                .and_then(|obj| obj.peel_tags_to_end().map_err(Into::into))
                .map(|obj| obj.id.attach(self.repo)),
            Kind::Symbolic(r) => r.attach(self.repo).peel_to_id_in_place().map_err(Into::into),
        })
    }
src/clone/checkout.rs (line 61)
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
        pub fn main_worktree(
            &mut self,
            mut progress: impl crate::Progress,
            should_interrupt: &AtomicBool,
        ) -> Result<(Repository, git_worktree::index::checkout::Outcome), Error> {
            let repo = self
                .repo
                .as_ref()
                .expect("still present as we never succeeded the worktree checkout yet");
            let workdir = repo.work_dir().ok_or_else(|| Error::BareRepository {
                git_dir: repo.git_dir().to_owned(),
            })?;
            let root_tree = match repo.head()?.peel_to_id_in_place().transpose()? {
                Some(id) => id.object().expect("downloaded from remote").peel_to_tree()?.id,
                None => {
                    return Ok((
                        self.repo.take().expect("still present"),
                        git_worktree::index::checkout::Outcome::default(),
                    ))
                }
            };
            let index = git_index::State::from_tree(&root_tree, |oid, buf| repo.objects.find_tree_iter(oid, buf).ok())
                .map_err(|err| Error::IndexFromTree {
                    id: root_tree,
                    source: err,
                })?;
            let mut index = git_index::File::from_state(index, repo.index_path());

            let mut opts = repo.config.checkout_options(repo.git_dir())?;
            opts.destination_is_initially_empty = true;

            let mut files = progress.add_child_with_id("checkout", *b"CLCF"); /* CLone Checkout Files */
            let mut bytes = progress.add_child_with_id("writing", *b"CLCB") /* CLone Checkout Bytes */;

            files.init(Some(index.entries().len()), crate::progress::count("files"));
            bytes.init(None, crate::progress::bytes());

            let start = std::time::Instant::now();
            let outcome = git_worktree::index::checkout(
                &mut index,
                workdir,
                {
                    let objects = repo.objects.clone().into_arc()?;
                    move |oid, buf| objects.find_blob(oid, buf)
                },
                &mut files,
                &mut bytes,
                should_interrupt,
                opts,
            )?;
            files.show_throughput(start);
            bytes.show_throughput(start);

            index.write(Default::default())?;
            Ok((self.repo.take().expect("still present"), outcome))
        }
src/revision/spec/parse/delegate/navigate.rs (line 145)
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    fn peel_until(&mut self, kind: PeelTo<'_>) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        let mut replacements = Replacements::default();
        let mut errors = Vec::new();
        let objs = self.objs[self.idx].as_mut()?;
        let repo = self.repo;

        match kind {
            PeelTo::ValidObject => {
                for obj in objs.iter() {
                    match repo.find_object(*obj) {
                        Ok(_) => {}
                        Err(err) => {
                            errors.push((*obj, err.into()));
                        }
                    };
                }
            }
            PeelTo::ObjectKind(kind) => {
                let peel = |obj| peel(repo, obj, kind);
                for obj in objs.iter() {
                    match peel(obj) {
                        Ok(replace) => replacements.push((*obj, replace)),
                        Err(err) => errors.push((*obj, err)),
                    }
                }
            }
            PeelTo::Path(path) => {
                let lookup_path = |obj: &ObjectId| {
                    let tree_id = peel(repo, obj, git_object::Kind::Tree)?;
                    if path.is_empty() {
                        return Ok(tree_id);
                    }
                    let tree = repo.find_object(tree_id)?.into_tree();
                    let entry =
                        tree.lookup_entry_by_path(git_path::from_bstr(path))?
                            .ok_or_else(|| Error::PathNotFound {
                                path: path.into(),
                                object: obj.attach(repo).shorten_or_id(),
                                tree: tree_id.attach(repo).shorten_or_id(),
                            })?;
                    Ok(entry.object_id())
                };
                for obj in objs.iter() {
                    match lookup_path(obj) {
                        Ok(replace) => replacements.push((*obj, replace)),
                        Err(err) => errors.push((*obj, err)),
                    }
                }
            }
            PeelTo::RecursiveTagObject => {
                for oid in objs.iter() {
                    match oid.attach(repo).object().and_then(|obj| obj.peel_tags_to_end()) {
                        Ok(obj) => replacements.push((*oid, obj.id)),
                        Err(err) => errors.push((*oid, err.into())),
                    }
                }
            }
        }

        handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
    }

    fn find(&mut self, regex: &BStr, negated: bool) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        #[cfg(not(feature = "regex"))]
        let matches = |message: &BStr| -> bool { message.contains_str(regex) ^ negated };
        #[cfg(feature = "regex")]
        let matches = match regex::bytes::Regex::new(regex.to_str_lossy().as_ref()) {
            Ok(compiled) => {
                let needs_regex = regex::escape(compiled.as_str()) != regex;
                move |message: &BStr| -> bool {
                    if needs_regex {
                        compiled.is_match(message) ^ negated
                    } else {
                        message.contains_str(regex) ^ negated
                    }
                }
            }
            Err(err) => {
                self.err.push(err.into());
                return None;
            }
        };

        match self.objs[self.idx].as_mut() {
            Some(objs) => {
                let repo = self.repo;
                let mut errors = Vec::new();
                let mut replacements = Replacements::default();
                for oid in objs.iter() {
                    match oid
                        .attach(repo)
                        .ancestors()
                        .sorting(Sorting::ByCommitTimeNewestFirst)
                        .all()
                    {
                        Ok(iter) => {
                            let mut matched = false;
                            let mut count = 0;
                            let commits = iter.map(|res| {
                                res.map_err(Error::from).and_then(|commit_id| {
                                    commit_id.object().map_err(Error::from).map(|obj| obj.into_commit())
                                })
                            });
                            for commit in commits {
                                count += 1;
                                match commit {
                                    Ok(commit) => {
                                        if matches(commit.message_raw_sloppy()) {
                                            replacements.push((*oid, commit.id));
                                            matched = true;
                                            break;
                                        }
                                    }
                                    Err(err) => errors.push((*oid, err)),
                                }
                            }
                            if !matched {
                                errors.push((
                                    *oid,
                                    Error::NoRegexMatch {
                                        regex: regex.into(),
                                        commits_searched: count,
                                        oid: oid.attach(repo).shorten_or_id(),
                                    },
                                ))
                            }
                        }
                        Err(err) => errors.push((*oid, err.into())),
                    }
                }
                handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
            }
            None => match self.repo.references() {
                Ok(references) => match references.all() {
                    Ok(references) => {
                        match self
                            .repo
                            .rev_walk(
                                references
                                    .peeled()
                                    .filter_map(Result::ok)
                                    .filter(|r| {
                                        r.id()
                                            .object()
                                            .ok()
                                            .map(|obj| obj.kind == git_object::Kind::Commit)
                                            .unwrap_or(false)
                                    })
                                    .filter_map(|r| r.detach().peeled),
                            )
                            .sorting(Sorting::ByCommitTimeNewestFirst)
                            .all()
                        {
                            Ok(iter) => {
                                let mut matched = false;
                                let mut count = 0;
                                let commits = iter.map(|res| {
                                    res.map_err(Error::from).and_then(|commit_id| {
                                        commit_id.object().map_err(Error::from).map(|obj| obj.into_commit())
                                    })
                                });
                                for commit in commits {
                                    count += 1;
                                    match commit {
                                        Ok(commit) => {
                                            if matches(commit.message_raw_sloppy()) {
                                                self.objs[self.idx]
                                                    .get_or_insert_with(HashSet::default)
                                                    .insert(commit.id);
                                                matched = true;
                                                break;
                                            }
                                        }
                                        Err(err) => self.err.push(err),
                                    }
                                }
                                if matched {
                                    Some(())
                                } else {
                                    self.err.push(Error::NoRegexMatchAllRefs {
                                        regex: regex.into(),
                                        commits_searched: count,
                                    });
                                    None
                                }
                            }
                            Err(err) => {
                                self.err.push(err.into());
                                None
                            }
                        }
                    }
                    Err(err) => {
                        self.err.push(err.into());
                        None
                    }
                },
                Err(err) => {
                    self.err.push(err.into());
                    None
                }
            },
        }
    }

Try to find the Object associated with this object id, and return None if it’s not available locally.

Note

There can only be one ObjectRef per Easy. To increase that limit, clone the Easy.

Turn this object id into a shortened id with a length in hex as configured by core.abbrev.

Examples found in repository?
src/id.rs (line 46)
45
46
47
    pub fn shorten_or_id(&self) -> git_hash::Prefix {
        self.shorten().unwrap_or_else(|_| self.inner.into())
    }
More examples
Hide additional examples
src/object/commit.rs (line 43)
41
42
43
44
    pub fn short_id(&self) -> Result<git_hash::Prefix, crate::id::shorten::Error> {
        use crate::ext::ObjectIdExt;
        self.id.attach(self.repo).shorten()
    }
src/commit.rs (line 39)
38
39
40
41
        pub fn format(self) -> Result<git_revision::describe::Format<'static>, Error> {
            let prefix = self.id.shorten()?;
            Ok(self.outcome.into_format(prefix.hex_len()))
        }
src/object/peel.rs (line 61)
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    pub fn peel_to_kind(mut self, kind: Kind) -> Result<Self, peel::to_kind::Error> {
        loop {
            match self.kind {
                our_kind if kind == our_kind => {
                    return Ok(self);
                }
                Kind::Commit => {
                    let tree_id = self
                        .try_to_commit_ref_iter()
                        .expect("commit")
                        .tree_id()
                        .expect("valid commit");
                    let repo = self.repo;
                    drop(self);
                    self = repo.find_object(tree_id)?;
                }
                Kind::Tag => {
                    let target_id = self.to_tag_ref_iter().target_id().expect("valid tag");
                    let repo = self.repo;
                    drop(self);
                    self = repo.find_object(target_id)?;
                }
                Kind::Tree | Kind::Blob => {
                    return Err(peel::to_kind::Error::NotFound {
                        oid: self.id().shorten().unwrap_or_else(|_| self.id.into()),
                        actual: self.kind,
                        expected: kind,
                    })
                }
            }
        }
    }
src/revision/spec/parse/error.rs (line 101)
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
    pub(crate) fn ambiguous(candidates: HashSet<ObjectId>, prefix: git_hash::Prefix, repo: &Repository) -> Self {
        #[derive(PartialOrd, Ord, Eq, PartialEq, Copy, Clone)]
        enum Order {
            Tag,
            Commit,
            Tree,
            Blob,
            Invalid,
        }
        let candidates = {
            let mut c: Vec<_> = candidates
                .into_iter()
                .map(|oid| {
                    let obj = repo.find_object(oid);
                    let order = match &obj {
                        Err(_) => Order::Invalid,
                        Ok(obj) => match obj.kind {
                            git_object::Kind::Tag => Order::Tag,
                            git_object::Kind::Commit => Order::Commit,
                            git_object::Kind::Tree => Order::Tree,
                            git_object::Kind::Blob => Order::Blob,
                        },
                    };
                    (oid, obj, order)
                })
                .collect();
            c.sort_by(|lhs, rhs| lhs.2.cmp(&rhs.2).then_with(|| lhs.0.cmp(&rhs.0)));
            c
        };
        Error::AmbiguousPrefix {
            prefix,
            info: candidates
                .into_iter()
                .map(|(oid, find_result, _)| {
                    let info = match find_result {
                        Ok(obj) => match obj.kind {
                            git_object::Kind::Tree | git_object::Kind::Blob => CandidateInfo::Object { kind: obj.kind },
                            git_object::Kind::Tag => {
                                let tag = obj.to_tag_ref();
                                CandidateInfo::Tag { name: tag.name.into() }
                            }
                            git_object::Kind::Commit => {
                                use bstr::ByteSlice;
                                let commit = obj.to_commit_ref();
                                CandidateInfo::Commit {
                                    date: commit.committer().time,
                                    title: commit.message().title.trim().into(),
                                }
                            }
                        },
                        Err(err) => CandidateInfo::FindError { source: err },
                    };
                    (oid.attach(repo).shorten().unwrap_or_else(|_| oid.into()), info)
                })
                .collect(),
        }
    }

Turn this object id into a shortened id with a length in hex as configured by core.abbrev, or default to a prefix which equals our id in the unlikely error case.

Examples found in repository?
src/object/tree/iter.rs (line 41)
35
36
37
38
39
40
41
42
43
44
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{:06o} {:>6} {}\t{}",
            self.mode() as u32,
            self.mode().as_str(),
            self.id().shorten_or_id(),
            self.filename()
        )
    }
More examples
Hide additional examples
src/revision/spec/parse/delegate/mod.rs (line 154)
146
147
148
149
150
151
152
153
154
155
156
157
        fn require_object_kind(repo: &Repository, obj: &git_hash::oid, kind: git_object::Kind) -> Result<(), Error> {
            let obj = repo.find_object(obj)?;
            if obj.kind == kind {
                Ok(())
            } else {
                Err(Error::ObjectKind {
                    actual: obj.kind,
                    expected: kind,
                    oid: obj.id.attach(repo).shorten_or_id(),
                })
            }
        }
src/revision/spec/parse/delegate/navigate.rs (line 37)
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    fn traverse(&mut self, kind: Traversal) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        let mut replacements = Replacements::default();
        let mut errors = Vec::new();
        let objs = self.objs[self.idx].as_mut()?;
        let repo = self.repo;

        for obj in objs.iter() {
            match kind {
                Traversal::NthParent(num) => {
                    match self.repo.find_object(*obj).map_err(Error::from).and_then(|obj| {
                        obj.try_into_commit().map_err(|err| {
                            let object::try_into::Error { actual, expected, id } = err;
                            Error::ObjectKind {
                                oid: id.attach(repo).shorten_or_id(),
                                actual,
                                expected,
                            }
                        })
                    }) {
                        Ok(commit) => match commit.parent_ids().nth(num.saturating_sub(1)) {
                            Some(id) => replacements.push((commit.id, id.detach())),
                            None => errors.push((
                                commit.id,
                                Error::ParentOutOfRange {
                                    oid: commit.id().shorten_or_id(),
                                    desired: num,
                                    available: commit.parent_ids().count(),
                                },
                            )),
                        },
                        Err(err) => errors.push((*obj, err)),
                    }
                }
                Traversal::NthAncestor(num) => {
                    let id = obj.attach(repo);
                    match id
                        .ancestors()
                        .first_parent_only()
                        .all()
                        .expect("cannot fail without sorting")
                        .skip(num)
                        .filter_map(Result::ok)
                        .next()
                    {
                        Some(id) => replacements.push((*obj, id.detach())),
                        None => errors.push((
                            *obj,
                            Error::AncestorOutOfRange {
                                oid: id.shorten_or_id(),
                                desired: num,
                                available: id
                                    .ancestors()
                                    .first_parent_only()
                                    .all()
                                    .expect("cannot fail without sorting")
                                    .skip(1)
                                    .count(),
                            },
                        )),
                    }
                }
            }
        }

        handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
    }

    fn peel_until(&mut self, kind: PeelTo<'_>) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        let mut replacements = Replacements::default();
        let mut errors = Vec::new();
        let objs = self.objs[self.idx].as_mut()?;
        let repo = self.repo;

        match kind {
            PeelTo::ValidObject => {
                for obj in objs.iter() {
                    match repo.find_object(*obj) {
                        Ok(_) => {}
                        Err(err) => {
                            errors.push((*obj, err.into()));
                        }
                    };
                }
            }
            PeelTo::ObjectKind(kind) => {
                let peel = |obj| peel(repo, obj, kind);
                for obj in objs.iter() {
                    match peel(obj) {
                        Ok(replace) => replacements.push((*obj, replace)),
                        Err(err) => errors.push((*obj, err)),
                    }
                }
            }
            PeelTo::Path(path) => {
                let lookup_path = |obj: &ObjectId| {
                    let tree_id = peel(repo, obj, git_object::Kind::Tree)?;
                    if path.is_empty() {
                        return Ok(tree_id);
                    }
                    let tree = repo.find_object(tree_id)?.into_tree();
                    let entry =
                        tree.lookup_entry_by_path(git_path::from_bstr(path))?
                            .ok_or_else(|| Error::PathNotFound {
                                path: path.into(),
                                object: obj.attach(repo).shorten_or_id(),
                                tree: tree_id.attach(repo).shorten_or_id(),
                            })?;
                    Ok(entry.object_id())
                };
                for obj in objs.iter() {
                    match lookup_path(obj) {
                        Ok(replace) => replacements.push((*obj, replace)),
                        Err(err) => errors.push((*obj, err)),
                    }
                }
            }
            PeelTo::RecursiveTagObject => {
                for oid in objs.iter() {
                    match oid.attach(repo).object().and_then(|obj| obj.peel_tags_to_end()) {
                        Ok(obj) => replacements.push((*oid, obj.id)),
                        Err(err) => errors.push((*oid, err.into())),
                    }
                }
            }
        }

        handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
    }

    fn find(&mut self, regex: &BStr, negated: bool) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        #[cfg(not(feature = "regex"))]
        let matches = |message: &BStr| -> bool { message.contains_str(regex) ^ negated };
        #[cfg(feature = "regex")]
        let matches = match regex::bytes::Regex::new(regex.to_str_lossy().as_ref()) {
            Ok(compiled) => {
                let needs_regex = regex::escape(compiled.as_str()) != regex;
                move |message: &BStr| -> bool {
                    if needs_regex {
                        compiled.is_match(message) ^ negated
                    } else {
                        message.contains_str(regex) ^ negated
                    }
                }
            }
            Err(err) => {
                self.err.push(err.into());
                return None;
            }
        };

        match self.objs[self.idx].as_mut() {
            Some(objs) => {
                let repo = self.repo;
                let mut errors = Vec::new();
                let mut replacements = Replacements::default();
                for oid in objs.iter() {
                    match oid
                        .attach(repo)
                        .ancestors()
                        .sorting(Sorting::ByCommitTimeNewestFirst)
                        .all()
                    {
                        Ok(iter) => {
                            let mut matched = false;
                            let mut count = 0;
                            let commits = iter.map(|res| {
                                res.map_err(Error::from).and_then(|commit_id| {
                                    commit_id.object().map_err(Error::from).map(|obj| obj.into_commit())
                                })
                            });
                            for commit in commits {
                                count += 1;
                                match commit {
                                    Ok(commit) => {
                                        if matches(commit.message_raw_sloppy()) {
                                            replacements.push((*oid, commit.id));
                                            matched = true;
                                            break;
                                        }
                                    }
                                    Err(err) => errors.push((*oid, err)),
                                }
                            }
                            if !matched {
                                errors.push((
                                    *oid,
                                    Error::NoRegexMatch {
                                        regex: regex.into(),
                                        commits_searched: count,
                                        oid: oid.attach(repo).shorten_or_id(),
                                    },
                                ))
                            }
                        }
                        Err(err) => errors.push((*oid, err.into())),
                    }
                }
                handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
            }
            None => match self.repo.references() {
                Ok(references) => match references.all() {
                    Ok(references) => {
                        match self
                            .repo
                            .rev_walk(
                                references
                                    .peeled()
                                    .filter_map(Result::ok)
                                    .filter(|r| {
                                        r.id()
                                            .object()
                                            .ok()
                                            .map(|obj| obj.kind == git_object::Kind::Commit)
                                            .unwrap_or(false)
                                    })
                                    .filter_map(|r| r.detach().peeled),
                            )
                            .sorting(Sorting::ByCommitTimeNewestFirst)
                            .all()
                        {
                            Ok(iter) => {
                                let mut matched = false;
                                let mut count = 0;
                                let commits = iter.map(|res| {
                                    res.map_err(Error::from).and_then(|commit_id| {
                                        commit_id.object().map_err(Error::from).map(|obj| obj.into_commit())
                                    })
                                });
                                for commit in commits {
                                    count += 1;
                                    match commit {
                                        Ok(commit) => {
                                            if matches(commit.message_raw_sloppy()) {
                                                self.objs[self.idx]
                                                    .get_or_insert_with(HashSet::default)
                                                    .insert(commit.id);
                                                matched = true;
                                                break;
                                            }
                                        }
                                        Err(err) => self.err.push(err),
                                    }
                                }
                                if matched {
                                    Some(())
                                } else {
                                    self.err.push(Error::NoRegexMatchAllRefs {
                                        regex: regex.into(),
                                        commits_searched: count,
                                    });
                                    None
                                }
                            }
                            Err(err) => {
                                self.err.push(err.into());
                                None
                            }
                        }
                    }
                    Err(err) => {
                        self.err.push(err.into());
                        None
                    }
                },
                Err(err) => {
                    self.err.push(err.into());
                    None
                }
            },
        }
    }

Turn this instance into its bare ObjectId.

Examples found in repository?
src/revision/spec/parse/delegate/mod.rs (line 212)
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    fn follow_refs_to_objects_if_needed(&mut self) -> Option<()> {
        assert_eq!(self.refs.len(), self.objs.len());
        let repo = self.repo;
        for (r, obj) in self.refs.iter().zip(self.objs.iter_mut()) {
            if let (_ref_opt @ Some(ref_), obj_opt @ None) = (r, obj) {
                if let Some(id) = ref_.target.try_id().map(ToOwned::to_owned).or_else(|| {
                    ref_.clone()
                        .attach(repo)
                        .peel_to_id_in_place()
                        .ok()
                        .map(|id| id.detach())
                }) {
                    obj_opt.get_or_insert_with(HashSet::default).insert(id);
                };
            };
        }
        Some(())
    }
More examples
Hide additional examples
src/revision/spec/parse/delegate/revision.rs (line 193)
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
    fn nth_checked_out_branch(&mut self, branch_no: usize) -> Option<()> {
        self.unset_disambiguate_call();
        fn prior_checkouts_iter<'a>(
            platform: &'a mut git_ref::file::log::iter::Platform<'static, '_>,
        ) -> Result<impl Iterator<Item = (BString, ObjectId)> + 'a, Error> {
            match platform.rev().ok().flatten() {
                Some(log) => Ok(log.filter_map(Result::ok).filter_map(|line| {
                    line.message
                        .strip_prefix(b"checkout: moving from ")
                        .and_then(|from_to| from_to.find(" to ").map(|pos| &from_to[..pos]))
                        .map(|from_branch| (from_branch.into(), line.previous_oid))
                })),
                None => Err(Error::MissingRefLog {
                    reference: "HEAD".into(),
                    action: "search prior checked out branch",
                }),
            }
        }

        let head = match self.repo.head() {
            Ok(head) => head,
            Err(err) => {
                self.err.push(err.into());
                return None;
            }
        };
        match prior_checkouts_iter(&mut head.log_iter()).map(|mut it| it.nth(branch_no.saturating_sub(1))) {
            Ok(Some((ref_name, id))) => {
                let id = match self.repo.find_reference(ref_name.as_bstr()) {
                    Ok(mut r) => {
                        let id = r.peel_to_id_in_place().map(|id| id.detach()).unwrap_or(id);
                        self.refs[self.idx] = Some(r.detach());
                        id
                    }
                    Err(_) => id,
                };
                self.objs[self.idx].get_or_insert_with(HashSet::default).insert(id);
                Some(())
            }
            Ok(None) => {
                self.err.push(Error::PriorCheckoutOutOfRange {
                    desired: branch_no,
                    available: prior_checkouts_iter(&mut head.log_iter())
                        .map(|it| it.count())
                        .unwrap_or(0),
                });
                None
            }
            Err(err) => {
                self.err.push(err);
                None
            }
        }
    }
src/revision/spec/parse/delegate/navigate.rs (line 44)
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
    fn traverse(&mut self, kind: Traversal) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        let mut replacements = Replacements::default();
        let mut errors = Vec::new();
        let objs = self.objs[self.idx].as_mut()?;
        let repo = self.repo;

        for obj in objs.iter() {
            match kind {
                Traversal::NthParent(num) => {
                    match self.repo.find_object(*obj).map_err(Error::from).and_then(|obj| {
                        obj.try_into_commit().map_err(|err| {
                            let object::try_into::Error { actual, expected, id } = err;
                            Error::ObjectKind {
                                oid: id.attach(repo).shorten_or_id(),
                                actual,
                                expected,
                            }
                        })
                    }) {
                        Ok(commit) => match commit.parent_ids().nth(num.saturating_sub(1)) {
                            Some(id) => replacements.push((commit.id, id.detach())),
                            None => errors.push((
                                commit.id,
                                Error::ParentOutOfRange {
                                    oid: commit.id().shorten_or_id(),
                                    desired: num,
                                    available: commit.parent_ids().count(),
                                },
                            )),
                        },
                        Err(err) => errors.push((*obj, err)),
                    }
                }
                Traversal::NthAncestor(num) => {
                    let id = obj.attach(repo);
                    match id
                        .ancestors()
                        .first_parent_only()
                        .all()
                        .expect("cannot fail without sorting")
                        .skip(num)
                        .filter_map(Result::ok)
                        .next()
                    {
                        Some(id) => replacements.push((*obj, id.detach())),
                        None => errors.push((
                            *obj,
                            Error::AncestorOutOfRange {
                                oid: id.shorten_or_id(),
                                desired: num,
                                available: id
                                    .ancestors()
                                    .first_parent_only()
                                    .all()
                                    .expect("cannot fail without sorting")
                                    .skip(1)
                                    .count(),
                            },
                        )),
                    }
                }
            }
        }

        handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
    }

Obtain a platform for traversing ancestors of this commit.

Note that unless error_on_missing_commit() is enabled, which be default it is not, one will always see an empty iteration even if this id is not a commit, instead of an error. If this is undesirable, it’s best to check for the correct object type before creating an iterator.

Examples found in repository?
src/object/commit.rs (line 135)
134
135
136
    pub fn ancestors(&self) -> revision::walk::Platform<'repo> {
        self.id().ancestors()
    }
More examples
Hide additional examples
src/revision/spec/parse/delegate/navigate.rs (line 60)
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    fn traverse(&mut self, kind: Traversal) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        let mut replacements = Replacements::default();
        let mut errors = Vec::new();
        let objs = self.objs[self.idx].as_mut()?;
        let repo = self.repo;

        for obj in objs.iter() {
            match kind {
                Traversal::NthParent(num) => {
                    match self.repo.find_object(*obj).map_err(Error::from).and_then(|obj| {
                        obj.try_into_commit().map_err(|err| {
                            let object::try_into::Error { actual, expected, id } = err;
                            Error::ObjectKind {
                                oid: id.attach(repo).shorten_or_id(),
                                actual,
                                expected,
                            }
                        })
                    }) {
                        Ok(commit) => match commit.parent_ids().nth(num.saturating_sub(1)) {
                            Some(id) => replacements.push((commit.id, id.detach())),
                            None => errors.push((
                                commit.id,
                                Error::ParentOutOfRange {
                                    oid: commit.id().shorten_or_id(),
                                    desired: num,
                                    available: commit.parent_ids().count(),
                                },
                            )),
                        },
                        Err(err) => errors.push((*obj, err)),
                    }
                }
                Traversal::NthAncestor(num) => {
                    let id = obj.attach(repo);
                    match id
                        .ancestors()
                        .first_parent_only()
                        .all()
                        .expect("cannot fail without sorting")
                        .skip(num)
                        .filter_map(Result::ok)
                        .next()
                    {
                        Some(id) => replacements.push((*obj, id.detach())),
                        None => errors.push((
                            *obj,
                            Error::AncestorOutOfRange {
                                oid: id.shorten_or_id(),
                                desired: num,
                                available: id
                                    .ancestors()
                                    .first_parent_only()
                                    .all()
                                    .expect("cannot fail without sorting")
                                    .skip(1)
                                    .count(),
                            },
                        )),
                    }
                }
            }
        }

        handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
    }

    fn peel_until(&mut self, kind: PeelTo<'_>) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        let mut replacements = Replacements::default();
        let mut errors = Vec::new();
        let objs = self.objs[self.idx].as_mut()?;
        let repo = self.repo;

        match kind {
            PeelTo::ValidObject => {
                for obj in objs.iter() {
                    match repo.find_object(*obj) {
                        Ok(_) => {}
                        Err(err) => {
                            errors.push((*obj, err.into()));
                        }
                    };
                }
            }
            PeelTo::ObjectKind(kind) => {
                let peel = |obj| peel(repo, obj, kind);
                for obj in objs.iter() {
                    match peel(obj) {
                        Ok(replace) => replacements.push((*obj, replace)),
                        Err(err) => errors.push((*obj, err)),
                    }
                }
            }
            PeelTo::Path(path) => {
                let lookup_path = |obj: &ObjectId| {
                    let tree_id = peel(repo, obj, git_object::Kind::Tree)?;
                    if path.is_empty() {
                        return Ok(tree_id);
                    }
                    let tree = repo.find_object(tree_id)?.into_tree();
                    let entry =
                        tree.lookup_entry_by_path(git_path::from_bstr(path))?
                            .ok_or_else(|| Error::PathNotFound {
                                path: path.into(),
                                object: obj.attach(repo).shorten_or_id(),
                                tree: tree_id.attach(repo).shorten_or_id(),
                            })?;
                    Ok(entry.object_id())
                };
                for obj in objs.iter() {
                    match lookup_path(obj) {
                        Ok(replace) => replacements.push((*obj, replace)),
                        Err(err) => errors.push((*obj, err)),
                    }
                }
            }
            PeelTo::RecursiveTagObject => {
                for oid in objs.iter() {
                    match oid.attach(repo).object().and_then(|obj| obj.peel_tags_to_end()) {
                        Ok(obj) => replacements.push((*oid, obj.id)),
                        Err(err) => errors.push((*oid, err.into())),
                    }
                }
            }
        }

        handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
    }

    fn find(&mut self, regex: &BStr, negated: bool) -> Option<()> {
        self.unset_disambiguate_call();
        self.follow_refs_to_objects_if_needed()?;

        #[cfg(not(feature = "regex"))]
        let matches = |message: &BStr| -> bool { message.contains_str(regex) ^ negated };
        #[cfg(feature = "regex")]
        let matches = match regex::bytes::Regex::new(regex.to_str_lossy().as_ref()) {
            Ok(compiled) => {
                let needs_regex = regex::escape(compiled.as_str()) != regex;
                move |message: &BStr| -> bool {
                    if needs_regex {
                        compiled.is_match(message) ^ negated
                    } else {
                        message.contains_str(regex) ^ negated
                    }
                }
            }
            Err(err) => {
                self.err.push(err.into());
                return None;
            }
        };

        match self.objs[self.idx].as_mut() {
            Some(objs) => {
                let repo = self.repo;
                let mut errors = Vec::new();
                let mut replacements = Replacements::default();
                for oid in objs.iter() {
                    match oid
                        .attach(repo)
                        .ancestors()
                        .sorting(Sorting::ByCommitTimeNewestFirst)
                        .all()
                    {
                        Ok(iter) => {
                            let mut matched = false;
                            let mut count = 0;
                            let commits = iter.map(|res| {
                                res.map_err(Error::from).and_then(|commit_id| {
                                    commit_id.object().map_err(Error::from).map(|obj| obj.into_commit())
                                })
                            });
                            for commit in commits {
                                count += 1;
                                match commit {
                                    Ok(commit) => {
                                        if matches(commit.message_raw_sloppy()) {
                                            replacements.push((*oid, commit.id));
                                            matched = true;
                                            break;
                                        }
                                    }
                                    Err(err) => errors.push((*oid, err)),
                                }
                            }
                            if !matched {
                                errors.push((
                                    *oid,
                                    Error::NoRegexMatch {
                                        regex: regex.into(),
                                        commits_searched: count,
                                        oid: oid.attach(repo).shorten_or_id(),
                                    },
                                ))
                            }
                        }
                        Err(err) => errors.push((*oid, err.into())),
                    }
                }
                handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
            }
            None => match self.repo.references() {
                Ok(references) => match references.all() {
                    Ok(references) => {
                        match self
                            .repo
                            .rev_walk(
                                references
                                    .peeled()
                                    .filter_map(Result::ok)
                                    .filter(|r| {
                                        r.id()
                                            .object()
                                            .ok()
                                            .map(|obj| obj.kind == git_object::Kind::Commit)
                                            .unwrap_or(false)
                                    })
                                    .filter_map(|r| r.detach().peeled),
                            )
                            .sorting(Sorting::ByCommitTimeNewestFirst)
                            .all()
                        {
                            Ok(iter) => {
                                let mut matched = false;
                                let mut count = 0;
                                let commits = iter.map(|res| {
                                    res.map_err(Error::from).and_then(|commit_id| {
                                        commit_id.object().map_err(Error::from).map(|obj| obj.into_commit())
                                    })
                                });
                                for commit in commits {
                                    count += 1;
                                    match commit {
                                        Ok(commit) => {
                                            if matches(commit.message_raw_sloppy()) {
                                                self.objs[self.idx]
                                                    .get_or_insert_with(HashSet::default)
                                                    .insert(commit.id);
                                                matched = true;
                                                break;
                                            }
                                        }
                                        Err(err) => self.err.push(err),
                                    }
                                }
                                if matched {
                                    Some(())
                                } else {
                                    self.err.push(Error::NoRegexMatchAllRefs {
                                        regex: regex.into(),
                                        commits_searched: count,
                                    });
                                    None
                                }
                            }
                            Err(err) => {
                                self.err.push(err.into());
                                None
                            }
                        }
                    }
                    Err(err) => {
                        self.err.push(err.into());
                        None
                    }
                },
                Err(err) => {
                    self.err.push(err.into());
                    None
                }
            },
        }
    }

Methods from Deref<Target = oid>§

The kind of hash used for this Digest

The first byte of the hash, commonly used to partition a set of Ids

Interpret this object id as raw byte slice.

Return a type which can display itself in hexadecimal form with the len amount of characters.

Return a type which displays this oid as hex in full.

Write ourselves to the out in hexadecimal notation, returning the amount of written bytes.

Panics if the buffer isn’t big enough to hold twice as many bytes as the current binary size.

Write ourselves to out in hexadecimal notation

Trait Implementations§

Converts this type into a shared reference of the (usually inferred) input type.
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
The resulting type after dereferencing.
Dereferences the value.
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= operator. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Should always be Self
Converts the given value to a [CompactString]. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Converts the given value to a String. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.