mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00
Avoid refreshing Git repo twice (#350)
This was a bug in the Git code (that I wrote, not from Cargo) -- when we `precise` the reference, we should store the resolved commit.
This commit is contained in:
parent
243549876c
commit
620afc3caf
2 changed files with 42 additions and 21 deletions
|
@ -32,17 +32,26 @@ pub(crate) enum GitReference {
|
||||||
Tag(String),
|
Tag(String),
|
||||||
/// From a reference that's ambiguously a branch or tag.
|
/// From a reference that's ambiguously a branch or tag.
|
||||||
BranchOrTag(String),
|
BranchOrTag(String),
|
||||||
/// From a specific revision. Can be a commit hash (either short or full),
|
/// From a specific revision, using a full 40-character commit hash.
|
||||||
/// or a named reference like `refs/pull/493/head`.
|
FullCommit(String),
|
||||||
Rev(String),
|
/// From a truncated revision.
|
||||||
|
ShortCommit(String),
|
||||||
|
/// From a named reference, like `refs/pull/493/head`.
|
||||||
|
Ref(String),
|
||||||
/// The default branch of the repository, the reference named `HEAD`.
|
/// The default branch of the repository, the reference named `HEAD`.
|
||||||
DefaultBranch,
|
DefaultBranch,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GitReference {
|
impl GitReference {
|
||||||
pub(crate) fn from_rev(rev: &str) -> Self {
|
pub(crate) fn from_rev(rev: &str) -> Self {
|
||||||
if looks_like_commit_hash(rev) || rev.starts_with("refs/") {
|
if rev.starts_with("refs/") {
|
||||||
Self::Rev(rev.to_owned())
|
Self::Ref(rev.to_owned())
|
||||||
|
} else if looks_like_commit_hash(rev) {
|
||||||
|
if rev.len() == 40 {
|
||||||
|
Self::FullCommit(rev.to_owned())
|
||||||
|
} else {
|
||||||
|
Self::ShortCommit(rev.to_owned())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Self::BranchOrTag(rev.to_owned())
|
Self::BranchOrTag(rev.to_owned())
|
||||||
}
|
}
|
||||||
|
@ -123,7 +132,7 @@ impl GitRemote {
|
||||||
strategy: FetchStrategy,
|
strategy: FetchStrategy,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
) -> Result<(GitDatabase, git2::Oid)> {
|
) -> Result<(GitDatabase, git2::Oid)> {
|
||||||
let locked_ref = locked_rev.map(|oid| GitReference::Rev(oid.to_string()));
|
let locked_ref = locked_rev.map(|oid| GitReference::FullCommit(oid.to_string()));
|
||||||
let reference = locked_ref.as_ref().unwrap_or(reference);
|
let reference = locked_ref.as_ref().unwrap_or(reference);
|
||||||
if let Some(mut db) = db {
|
if let Some(mut db) = db {
|
||||||
fetch(&mut db.repo, self.url.as_str(), reference, strategy, client)
|
fetch(&mut db.repo, self.url.as_str(), reference, strategy, client)
|
||||||
|
@ -262,7 +271,7 @@ impl GitReference {
|
||||||
head.peel(ObjectType::Commit)?.id()
|
head.peel(ObjectType::Commit)?.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
GitReference::Rev(s) => {
|
GitReference::FullCommit(s) | GitReference::ShortCommit(s) | GitReference::Ref(s) => {
|
||||||
let obj = repo.revparse_single(s)?;
|
let obj = repo.revparse_single(s)?;
|
||||||
match obj.as_tag() {
|
match obj.as_tag() {
|
||||||
Some(tag) => tag.target_id(),
|
Some(tag) => tag.target_id(),
|
||||||
|
@ -483,7 +492,7 @@ impl<'a> GitCheckout<'a> {
|
||||||
|
|
||||||
// Fetch data from origin and reset to the head commit
|
// Fetch data from origin and reset to the head commit
|
||||||
debug!("Updating Git submodule: {}", child_remote_url);
|
debug!("Updating Git submodule: {}", child_remote_url);
|
||||||
let reference = GitReference::Rev(head.to_string());
|
let reference = GitReference::FullCommit(head.to_string());
|
||||||
fetch(&mut repo, &child_remote_url, &reference, strategy, client).with_context(
|
fetch(&mut repo, &child_remote_url, &reference, strategy, client).with_context(
|
||||||
|| {
|
|| {
|
||||||
format!(
|
format!(
|
||||||
|
@ -917,14 +926,14 @@ pub(crate) fn fetch(
|
||||||
refspecs.push(String::from("+HEAD:refs/remotes/origin/HEAD"));
|
refspecs.push(String::from("+HEAD:refs/remotes/origin/HEAD"));
|
||||||
}
|
}
|
||||||
|
|
||||||
GitReference::Rev(rev) => {
|
GitReference::Ref(rev) => {
|
||||||
if rev.starts_with("refs/") {
|
refspecs.push(format!("+{rev}:{rev}"));
|
||||||
refspecs.push(format!("+{rev}:{rev}"));
|
}
|
||||||
} else if let Some(oid_to_fetch) = oid_to_fetch {
|
|
||||||
|
GitReference::FullCommit(rev) => {
|
||||||
|
if let Some(oid_to_fetch) = oid_to_fetch {
|
||||||
refspecs.push(format!("+{oid_to_fetch}:refs/commit/{oid_to_fetch}"));
|
refspecs.push(format!("+{oid_to_fetch}:refs/commit/{oid_to_fetch}"));
|
||||||
} else if rev.parse::<git2::Oid>().is_ok()
|
} else {
|
||||||
&& (rev.len() == 40 || rev.starts_with("refs/"))
|
|
||||||
{
|
|
||||||
// There is a specific commit to fetch and we will do so in shallow-mode only
|
// There is a specific commit to fetch and we will do so in shallow-mode only
|
||||||
// to not disturb the previous logic.
|
// to not disturb the previous logic.
|
||||||
// Note that with typical settings for shallowing, we will just fetch a single `rev`
|
// Note that with typical settings for shallowing, we will just fetch a single `rev`
|
||||||
|
@ -932,6 +941,12 @@ pub(crate) fn fetch(
|
||||||
// The reason we write to `refs/remotes/origin/HEAD` is that it's of special significance
|
// The reason we write to `refs/remotes/origin/HEAD` is that it's of special significance
|
||||||
// when during `GitReference::resolve()`, but otherwise it shouldn't matter.
|
// when during `GitReference::resolve()`, but otherwise it shouldn't matter.
|
||||||
refspecs.push(format!("+{rev}:refs/remotes/origin/HEAD"));
|
refspecs.push(format!("+{rev}:refs/remotes/origin/HEAD"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GitReference::ShortCommit(_) => {
|
||||||
|
if let Some(oid_to_fetch) = oid_to_fetch {
|
||||||
|
refspecs.push(format!("+{oid_to_fetch}:refs/commit/{oid_to_fetch}"));
|
||||||
} else {
|
} else {
|
||||||
// We don't know what the rev will point to. To handle this
|
// We don't know what the rev will point to. To handle this
|
||||||
// situation we fetch all branches and tags, and then we pray
|
// situation we fetch all branches and tags, and then we pray
|
||||||
|
@ -1216,10 +1231,9 @@ fn github_fast_path(
|
||||||
GitReference::Tag(tag) => tag,
|
GitReference::Tag(tag) => tag,
|
||||||
GitReference::BranchOrTag(branch_or_tag) => branch_or_tag,
|
GitReference::BranchOrTag(branch_or_tag) => branch_or_tag,
|
||||||
GitReference::DefaultBranch => "HEAD",
|
GitReference::DefaultBranch => "HEAD",
|
||||||
GitReference::Rev(rev) => {
|
GitReference::Ref(rev) => rev,
|
||||||
if rev.starts_with("refs/") {
|
GitReference::FullCommit(rev) | GitReference::ShortCommit(rev) => {
|
||||||
rev
|
if looks_like_commit_hash(rev) {
|
||||||
} else if looks_like_commit_hash(rev) {
|
|
||||||
// `revparse_single` (used by `resolve`) is the only way to turn
|
// `revparse_single` (used by `resolve`) is the only way to turn
|
||||||
// short hash -> long hash, but it also parses other things,
|
// short hash -> long hash, but it also parses other things,
|
||||||
// like branch and tag names, which might coincidentally be
|
// like branch and tag names, which might coincidentally be
|
||||||
|
|
|
@ -42,11 +42,16 @@ impl TryFrom<Url> for Git {
|
||||||
reference = GitReference::from_rev(rev);
|
reference = GitReference::from_rev(rev);
|
||||||
url = Url::parse(prefix)?;
|
url = Url::parse(prefix)?;
|
||||||
}
|
}
|
||||||
|
let precise = if let GitReference::FullCommit(rev) = &reference {
|
||||||
|
Some(git2::Oid::from_str(rev)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
url,
|
url,
|
||||||
reference,
|
reference,
|
||||||
precise: None,
|
precise,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +69,9 @@ impl From<Git> for Url {
|
||||||
GitReference::Branch(rev)
|
GitReference::Branch(rev)
|
||||||
| GitReference::Tag(rev)
|
| GitReference::Tag(rev)
|
||||||
| GitReference::BranchOrTag(rev)
|
| GitReference::BranchOrTag(rev)
|
||||||
| GitReference::Rev(rev) => {
|
| GitReference::Ref(rev)
|
||||||
|
| GitReference::FullCommit(rev)
|
||||||
|
| GitReference::ShortCommit(rev) => {
|
||||||
url.set_path(&format!("{}@{}", url.path(), rev));
|
url.set_path(&format!("{}@{}", url.path(), rev));
|
||||||
}
|
}
|
||||||
GitReference::DefaultBranch => {}
|
GitReference::DefaultBranch => {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue