将瞬态 git 依赖项修补到特定版本

Patch a transient git dependency to a specific rev

我依赖 crates ab,我将 b 修补为 git 对 ref 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 也依赖于 b 作为 git 依赖,但没有特定的 ref:

# Cargo.toml of a
[dependencies]
b = { git = "https://github.com/user/example" }

我想强制 a 像我一样对 b 使用相同的 ref,我认为我可以这样做:

# 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" }

但这不起作用,因为我正在修补的源仍然指向相同的源,只是在不同的 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]

到目前为止,我的解决方法是分叉 b 并像这样打补丁:

# 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 hack,但它也不起作用,因为它只是忽略了 rev。整个 GitHub 问题使它看起来像我正在尝试的目前不受支持,但很难说,因为它不是完全相同的功能。

根据 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,但货物仍然只是比较 URL,没有别的。
然而,我们可以利用这个“特性”来发挥我们的优势:在 URL 的末尾添加一个 ?ref=foo 将使它看起来像一个新的来源:

# 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" }

小心使用两个补丁中的URL hack,否则你会创建一个带有两个b定义的损坏Cargo.lock :

# 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" }

虽然我没有测试它,但原则上,这种方法应该也适用于分支上的补丁,方法是将 /tree/<branch> 附加到 URL.