Skip to content

Commit dbff32b

Browse files
committed
Auto merge of #10079 - dtolnay-contrib:fetch, r=ehuss
Fetch GitHub commits by long hash more efficiently Closes #10078. **Tested with the following Cargo.toml:** ```toml [package] name = "repro" version = "0.0.0" edition = "2021" publish = false [dependencies] cargo = { git = "https://github.com/rust-lang/cargo", rev = "b30694b4d9b29141298870b7993e9aee10940524" } ``` ```console $ rm -rf ~/.cargo/git/db/cargo-* ~/.cargo/git/checkouts/cargo-* $ time $CARGO generate-lockfile $ du -shc ~/.cargo/git/db/cargo-* ~/.cargo/git/checkouts/cargo-* ``` Using current cargo from the most recent nightly, the `generate-lockfile` command downloads 69704 git objects in 7.0 seconds, consuming 41 MB on disk. Using cargo built from this PR by `cargo build --release`, the same command downloads 21481 objects in 2.2 seconds, consuming 17 MB on disk. Once libgit2 is able to do shallow clones (libgit2/libgit2#3058) this can be even more of a speedup. Using command-line git (which does not use libgit2) and `time git fetch --depth=1 https://github.com/rust-lang/cargo b30694b` indicates that it downloads just 262 objects in 1.1 seconds.
2 parents 47620e2 + 7da3c36 commit dbff32b

File tree

1 file changed

+14
-1
lines changed

1 file changed

+14
-1
lines changed

src/cargo/sources/git/utils.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,8 +815,11 @@ pub fn fetch(
815815
}
816816

817817
GitReference::Rev(rev) => {
818+
let is_github = || Url::parse(url).map_or(false, |url| is_github(&url));
818819
if rev.starts_with("refs/") {
819820
refspecs.push(format!("+{0}:{0}", rev));
821+
} else if is_github() && is_long_hash(rev) {
822+
refspecs.push(format!("+{0}:refs/commit/{0}", rev));
820823
} else {
821824
// We don't know what the rev will point to. To handle this
822825
// situation we fetch all branches and tags, and then we pray
@@ -1036,7 +1039,7 @@ fn github_up_to_date(
10361039
config: &Config,
10371040
) -> CargoResult<bool> {
10381041
let url = Url::parse(url)?;
1039-
if url.host_str() != Some("github.com") {
1042+
if !is_github(&url) {
10401043
return Ok(false);
10411044
}
10421045

@@ -1047,6 +1050,8 @@ fn github_up_to_date(
10471050
GitReference::Rev(rev) => {
10481051
if rev.starts_with("refs/") {
10491052
rev
1053+
} else if is_long_hash(rev) {
1054+
return Ok(reference.resolve(repo).is_ok());
10501055
} else {
10511056
debug!("can't use github fast path with `rev = \"{}\"`", rev);
10521057
return Ok(false);
@@ -1089,3 +1094,11 @@ fn github_up_to_date(
10891094
handle.perform()?;
10901095
Ok(handle.response_code()? == 304)
10911096
}
1097+
1098+
fn is_github(url: &Url) -> bool {
1099+
url.host_str() == Some("github.com")
1100+
}
1101+
1102+
fn is_long_hash(rev: &str) -> bool {
1103+
rev.len() == 40 && rev.chars().all(|ch| ch.is_ascii_hexdigit())
1104+
}

0 commit comments

Comments
 (0)