From 256213a6554fc3c15aac36ee244400e15f82016b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Aug 2021 18:15:05 -0700 Subject: [PATCH 1/4] Allow dependency's rev to refer to a ref by name --- src/cargo/sources/git/utils.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 5979f430c38..d46c50820c4 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -799,13 +799,17 @@ pub fn fetch( refspecs.push(String::from("HEAD:refs/remotes/origin/HEAD")); } - // For `rev` dependencies we don't know what the rev will point to. To - // handle this situation we fetch all branches and tags, and then we - // pray it's somewhere in there. - GitReference::Rev(_) => { - refspecs.push(String::from("refs/heads/*:refs/remotes/origin/*")); - refspecs.push(String::from("HEAD:refs/remotes/origin/HEAD")); - tags = true; + GitReference::Rev(rev) => { + if rev.starts_with("refs/") { + refspecs.push(format!("{0}:{0}", rev)); + } else { + // We don't know what the rev will point to. To handle this + // situation we fetch all branches and tags, and then we pray + // it's somewhere in there. + refspecs.push(String::from("refs/heads/*:refs/remotes/origin/*")); + refspecs.push(String::from("HEAD:refs/remotes/origin/HEAD")); + tags = true; + } } } From 361b11000ad78c4ed4401ad2ac475424b7edb836 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Aug 2021 18:48:02 -0700 Subject: [PATCH 2/4] Add test of git dependency on pull request --- tests/testsuite/git.rs | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index 46830457fc0..d7974a3ef87 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -230,6 +230,68 @@ fn cargo_compile_git_dep_tag() { project.cargo("build").run(); } +#[cargo_test] +fn cargo_compile_git_dep_pull_request() { + let project = project(); + let git_project = git::new("dep1", |project| { + project + .file("Cargo.toml", &basic_lib_manifest("dep1")) + .file( + "src/dep1.rs", + r#" + pub fn hello() -> &'static str { + "hello world" + } + "#, + ) + }); + + // Make a reference in GitHub's pull request ref naming convention. + let repo = git2::Repository::open(&git_project.root()).unwrap(); + let oid = repo.refname_to_id("HEAD").unwrap(); + let force = false; + let log_message = "open pull request"; + repo.reference("refs/pull/330/head", oid, force, log_message) + .unwrap(); + + let project = project + .file( + "Cargo.toml", + &format!( + r#" + [project] + name = "foo" + version = "0.0.0" + + [dependencies] + dep1 = {{ git = "{}", rev = "refs/pull/330/head" }} + "#, + git_project.url() + ), + ) + .file( + "src/main.rs", + &main_file(r#""{}", dep1::hello()"#, &["dep1"]), + ) + .build(); + + let git_root = git_project.root(); + + project + .cargo("build") + .with_stderr(&format!( + "[UPDATING] git repository `{}`\n\ + [COMPILING] dep1 v0.5.0 ({}?rev=refs/pull/330/head#[..])\n\ + [COMPILING] foo v0.0.0 ([CWD])\n\ + [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n", + path2url(&git_root), + path2url(&git_root), + )) + .run(); + + assert!(project.bin("foo").is_file()); +} + #[cargo_test] fn cargo_compile_with_nested_paths() { let git_project = git::new("dep1", |project| { From 19bb1df2266680c666878b08e55e08254c687708 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 31 Aug 2021 11:11:32 -0700 Subject: [PATCH 3/4] Allow `rev = "refs/..."` to use the GitHub fast path --- src/cargo/sources/git/utils.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index d46c50820c4..507ba90bb1b 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -1029,9 +1029,13 @@ fn github_up_to_date( GitReference::Branch(branch) => branch, GitReference::Tag(tag) => tag, GitReference::DefaultBranch => "HEAD", - GitReference::Rev(_) => { - debug!("can't use github fast path with `rev`"); - return Ok(false); + GitReference::Rev(rev) => { + if rev.starts_with("refs/") { + rev + } else { + debug!("can't use github fast path with `rev = \"{}\"`", rev); + return Ok(false); + } } }; From 86276d4ffe1cc644a46c138e18a4b414c55f673c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 1 Sep 2021 00:41:23 -0700 Subject: [PATCH 4/4] Document the use of `rev` to depend on pull requests --- src/doc/src/reference/specifying-dependencies.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/doc/src/reference/specifying-dependencies.md b/src/doc/src/reference/specifying-dependencies.md index 62789a4b879..d60d523bd92 100644 --- a/src/doc/src/reference/specifying-dependencies.md +++ b/src/doc/src/reference/specifying-dependencies.md @@ -147,6 +147,13 @@ the latest commit on a branch named `next`: regex = { git = "https://github.com/rust-lang/regex", branch = "next" } ``` +Anything that is not a branch or tag falls under `rev`. This can be a commit +hash like `rev = "4c59b707"`, or a named reference exposed by the remote +repository such as `rev = "refs/pull/493/head"`. What references are available +varies by where the repo is hosted; GitHub in particular exposes a reference to +the most recent commit of every pull request as shown, but other git hosts often +provide something equivalent, possibly under a different naming scheme. + Once a `git` dependency has been added, Cargo will lock that dependency to the latest commit at the time. New commits will not be pulled down automatically once the lock is in place. However, they can be pulled down manually with