forked from mirrors/jj
git: on import_refs(), avoid loading git commit object if it's known
With my colocated "linux" repo, this appears to save ~50ms startup overhead. Since the repo has lots of indirect tags, we can't eliminate tag object loading at all. But still, it's faster than falling back to peel_to_commit().
This commit is contained in:
parent
e6ab3f132f
commit
d1701a5d95
1 changed files with 45 additions and 7 deletions
|
@ -60,6 +60,44 @@ fn local_branch_name_to_ref_name(branch: &str) -> String {
|
||||||
format!("refs/heads/{branch}")
|
format!("refs/heads/{branch}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if `git_ref` points to a Git commit object, and returns its id.
|
||||||
|
///
|
||||||
|
/// If the ref points to the previously `known_target` (i.e. unchanged), this
|
||||||
|
/// should be faster than `git_ref.peel_to_commit()`.
|
||||||
|
fn resolve_git_ref_to_commit_id(
|
||||||
|
git_ref: &git2::Reference<'_>,
|
||||||
|
known_target: Option<&RefTarget>,
|
||||||
|
) -> Option<CommitId> {
|
||||||
|
// Try fast path if we have a candidate id which is known to be a commit object.
|
||||||
|
if let Some(RefTarget::Normal(id)) = known_target {
|
||||||
|
if matches!(git_ref.target(), Some(oid) if oid.as_bytes() == id.as_bytes()) {
|
||||||
|
return Some(id.clone());
|
||||||
|
}
|
||||||
|
if matches!(git_ref.target_peel(), Some(oid) if oid.as_bytes() == id.as_bytes()) {
|
||||||
|
// Perhaps an annotated tag stored in packed-refs file, and pointing to the
|
||||||
|
// already known target commit.
|
||||||
|
return Some(id.clone());
|
||||||
|
}
|
||||||
|
// A tag (according to ref name.) Try to peel one more level. This is slightly
|
||||||
|
// faster than recurse into peel_to_commit(). If we recorded a tag oid, we
|
||||||
|
// could skip this at all.
|
||||||
|
if let Some(Ok(tag)) = git_ref.is_tag().then(|| git_ref.peel_to_tag()) {
|
||||||
|
if tag.target_id().as_bytes() == id.as_bytes() {
|
||||||
|
// An annotated tag pointing to the already known target commit.
|
||||||
|
return Some(id.clone());
|
||||||
|
} else {
|
||||||
|
// Unknown id. Recurse from the current state as git_object_peel() of
|
||||||
|
// libgit2 would do. A tag may point to non-commit object.
|
||||||
|
let git_commit = tag.into_object().peel_to_commit().ok()?;
|
||||||
|
return Some(CommitId::from_bytes(git_commit.id().as_bytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let git_commit = git_ref.peel_to_commit().ok()?;
|
||||||
|
Some(CommitId::from_bytes(git_commit.id().as_bytes()))
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Eventually, git-tracking branches should no longer be stored in
|
// TODO: Eventually, git-tracking branches should no longer be stored in
|
||||||
// git_refs but with the other remote-tracking branches in BranchTarget. Note
|
// git_refs but with the other remote-tracking branches in BranchTarget. Note
|
||||||
// that there are important but subtle differences in behavior for, e.g. `jj
|
// that there are important but subtle differences in behavior for, e.g. `jj
|
||||||
|
@ -150,14 +188,14 @@ pub fn import_some_refs(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let git_commit = match git_repo_ref.peel_to_commit() {
|
let id = if let Some(id) =
|
||||||
Ok(git_commit) => git_commit,
|
resolve_git_ref_to_commit_id(&git_repo_ref, jj_view_git_refs.get(&full_name))
|
||||||
Err(_) => {
|
{
|
||||||
// Perhaps a tag pointing to a GPG key or similar. Just skip it.
|
id
|
||||||
|
} else {
|
||||||
|
// Skip invalid refs.
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let id = CommitId::from_bytes(git_commit.id().as_bytes());
|
|
||||||
pinned_git_heads.insert(full_name.to_string(), vec![id.clone()]);
|
pinned_git_heads.insert(full_name.to_string(), vec![id.clone()]);
|
||||||
if !git_ref_filter(&full_name) {
|
if !git_ref_filter(&full_name) {
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in a new issue