I depend on crates a
and b
, where I patched b
to a git dependency on rev
foo
:
# Cargo.toml of my crate
[dependencies]
a = "1.0.0"
b = "1.0.0"
[patch.crates-io]
b = { git = "https://github.com/user/example", rev = "foo" }
a
also depends on b
as a git dependency, but on no specific rev
:
# Cargo.toml of a
[dependencies]
b = { git = "https://github.com/user/example" }
I want to force a
to use the same rev
for b
as I do, which I thought I could do like this:
# The ideal Cargo.toml of my crate
[dependencies]
a = "1.0.0"
b = "1.0.0"
# patch local dependency
[patch.crates-io]
b = { git = "https://github.com/user/example", rev = "foo" }
# patch transient dependency
[patch.'https://github.com/user/example']
b = { git = "https://github.com/user/example", rev = "foo" }
This does not work however, since the source I'm patching still points to the same source, just in a different rev
:
error: failed to resolve patches for `https://github.com/user/example`
Caused by:
patch for `b` in `https://github.com/user/example` points to the same source, but patches must point to different sources
[Finished running. Exit status: 101]
My workaround so far is to fork b
and patch like this:
# Cargo.toml of my crate using a work around
[dependencies]
a = "1.0.0"
b = "1.0.0"
[patch.crates-io]
b = { git = "https://github.com/me/example", rev = "foo" } # Using my fork
[patch.'https://github.com/user/example']
b = { git = "https://github.com/me/example", rev = "foo" } # Using my fork
This works, but the fork is essentially useless. Is there a better way to do this?
I tried this hack, but it does not work either since it just ignores the rev
. The whole GitHub issue makes it look like what I'm trying is not supported at the moment, but it's hard to tell, since it's not exactly the same feature.
Per this GitHub issue, this feature is currently not supported, since git dependencies are differentiated exclusively via URL, not revision. Some URLs are treated as the same, e.g. the .git
ending always being stripped, but cargo is still just comparing URLs and nothing else.
We can however use this "feature" to our advantage: Adding a ?ref=foo
to the end of the URL will make it look like a new source:
# Fixed Cargo.toml
[dependencies]
a = "1.0.0"
b = "1.0.0"
# patch local dependency
[patch.crates-io]
b = { git = "https://github.com/user/example?rev=foo" }
# patch transient dependency
[patch.'https://github.com/user/example']
b = { git = "https://github.com/user/example?rev=foo" }
Be careful to use the URL hack in both patches, otherwise you will create a corrupt Cargo.lock
with two definitions of b
:
# Corrupt Cargo.toml
[dependencies]
a = "1.0.0"
b = "1.0.0"
# patch local dependency
[patch.crates-io]
b = { git = "https://github.com/user/example", rev = "foo" } # mistake!
# patch transient dependency
[patch.'https://github.com/user/example']
b = { git = "https://github.com/user/example?rev=foo" }
While I did not test it, this approach should in principle also work with patches on branches by appending /tree/<branch>
to the URL.