Open liskin opened 1 month ago
Thanks for the report and the reproducible example!
We can look at this issue from several different angles.
It could be argued that
cargo update
will never produce such inconsistencies inCargo.lock
.
Cargo only distinguishes Git dependencies by the provided rev
, branch
, or tag
value. If two Git dependencies are on the same branch or tag, they are considered coming from the same Git source. That being said, Cargo already supports depending on different revision today, via the rev
field.
Hence, the argument is correct. If not it is definitely a bug.
In your case, it is kinda like Git merge algorithm contributing to this bug. A merge-conflict friendly lockfile is undoubtedly a thing we try to achieve. https://github.com/rust-lang/cargo/issues/13300 is a recent issue that manual edits cause weird lockfile behavior. There is also an idea that we could use a custom merge driver https://github.com/rust-lang/cargo/issues/1818.
In the absence of
--locked
, I'm not sure if I want to see an error or if Cargo.lock should be updated. Certainly it shouldn't just silently pick one though.
Yeah I don't think Cargo should just error out in this case. A previously working lockfile shouldn't become invalid in future version of Cargo, unless the lockfile version has been bumped (don't worry if you've never heard of it; that version should be opaque to normal end users). Even though, Cargo should try upgrading the old version to the new one. This kind of fix is not trivial. However, I think the first step of this could be a warning, letting user know that Cargo is randomly picking a revision because the lockile was manually edtied to a inconsistent state. After that we can consider a lockfile version bump https://github.com/rust-lang/cargo/issues/12120.
Problem
Given multiple dependencies fetched from the same git repo, e.g.:
and
Cargo.lock
referring to multiple different git refs, e.g.:cargo tree
(and evencargo build
) will silently pick one of those git refs, ignoring the rest. All crates from the git repo will be built from the same revision, despiteCargo.lock
specifying otherwise. No error or warning is emitted, andCargo.lock
isn't updated to reflect the actual revisions that end up being used.The behaviour I expect is an error if
--locked
is passed to cargo.In the absence of
--locked
, I'm not sure if I want to see an error or ifCargo.lock
should be updated. Certainly it shouldn't just silently pick one though.Alternatively, cargo could actually support having several different revisions for a single git repo. After all, if the crates in question were published into the registry, there'd be no problem of them having different versions.
Steps
cargo init
,cargo build
,git add .
,git commit
cargo add --git https://github.com/tokio-rs/tracing --branch v0.1.x tracing tracing-subscriber
,git commit
cargo update --precise 8b7a1dde69797b33ecfa20da71e72eb5e61f0b25 tracing
,git commit
git checkout -p @^
(select only thetracing-core
hunk)cargo tree
— alltracing*
crates are at6d00d7d9
, butCargo.lock
still specifies8b7a1dde…
for most of them(the above steps executed today are captured in the following git repo for future reference: https://github.com/liskin/2024-07-10-cargo-lock-git-bug)
Possible Solution(s)
No response
Notes
It could be argued that
cargo update
will never produce such inconsistencies inCargo.lock
. Indeed, it was a "race condition" between two git pull requests: one person adding another dep from the repo, another bumping the revision of the existing deps. After merging the two independent PRs, we ended up with inconsistent revisions inCargo.lock
and were baffled why we can't use code that should now be available after the revision bump.This was not an isolated incident. I went to check the rest of our codebase and found another instance of multiple different revs for a single git repo in
Cargo.lock
. So I'd argue this is not super rare, and should be handled by cargo somehow.Version