I'm trying to build a mental model of what I expect dep to do, and where I'm at is approximately:
dep ensure -updatedep ensure && dep prune to make sure all is right in the worldSo from this worldview I would expect my toml file for a binary to be empty most of the time.
But then I want to vendor a package before using it, so I go to the README and I'm told to use dep ensure -add. Ok.
But now I have a constraint in my toml file! Why? Am I not supposed not to have any?
So I go to the issue tracker and search for wisdom, and I find https://github.com/golang/dep/issues/1054#issuecomment-325154327 which actually makes me feel like my understanding is mostly correct, but then why does dep ensure -add add a constraint?
So I'm confused.
A related thing I'm confused on is: should I have constraints pinning the major version of everything I use directly? If so, why doesn't dep ensure -add add one of those instead?
- the lock file depends from the imports, not from the toml, except for "required"
required, but also ignored - they're dual to each other in their effect on depgraph. required is literally the equivalent to an import statement (though i'm currently pondering softening that a tad to facilitate #1306). ignored is really the more powerful one as it's unique - it lets you basically blackhole a node in the import graph. some more on it in the old gps docs.
- the toml file is only for exceptions, specific constraints, and maybe libraries (unclear on this last one)
you _could_ operate that way - @nathany made an argument for an approach that scarcely used Gopkg.toml at all in #213. and doing so wouldn't be fundamentally wrong (as my comments in that post indicate). assuming you've reached a Gopkg.lock that works for you, then the only real drawback for a binary-only project would be that your dep ensure -update might be a bit of a wild and wooly experience. without a constraint, you could end up hopping from semver to branches to tags to... 🤷♂️
and that's generally why we've leaned away from recommending that route - it's can make updates a lot crazier. that's particularly the case when, say, you have A -> B -> C and A -> D -> C, B and D don't agree on C very well, but there's some _really_ old version of B that doesn't require C at all. without constraints to guide it away from that super old version, dep will likely end up picking the very old version of B. version constraints can do a lot to help narrow the field.
that, and because we've tried to dep in such a way that your use of it for "binary" vs. "lib" projects is basically the same - we, intentionally, do not distinguish between these.
But now I have a constraint in my toml file! Why? Am I not supposed not to have any?
so right, the above is why we append the constraint: it's based on the observation that the version we happened to grab just now is the first version that's guaranteed to have all the things you _might_ use from that dependency. so, we stick it in Gopkg.toml in order to keep your project on a sane, likely-to-work path - whether that's the purpose of your own dep ensure -updates later, or if the project is being brought in as something else's dependency.
Ok, so it was the other way around: I should always use dep ensure -add, and always have constraints. (For fuzzy values of "always".)
The final piece here was:
Note: When you specify a version without an operator, dep automatically uses the ^ operator by default.
To be fair, the README says to just use dep ensure -add to add deps, even if it says that after mentioning that imports win.
I think the dep ensure -add docs in the README would benefit from mentioning that the added constraint is major-range, even if it's explained below.
Maybe even explicitly say "you could have imports w/o constraints, but that might make your updates weird, don't do that".
(Thanks for the patient explanations, @sdboyer.)
Most helpful comment
required, but alsoignored- they're dual to each other in their effect on depgraph.requiredis literally the equivalent to animportstatement (though i'm currently pondering softening that a tad to facilitate #1306).ignoredis really the more powerful one as it's unique - it lets you basically blackhole a node in the import graph. some more on it in the old gps docs.you _could_ operate that way - @nathany made an argument for an approach that scarcely used
Gopkg.tomlat all in #213. and doing so wouldn't be fundamentally wrong (as my comments in that post indicate). assuming you've reached aGopkg.lockthat works for you, then the only real drawback for a binary-only project would be that yourdep ensure -updatemight be a bit of a wild and wooly experience. without a constraint, you could end up hopping from semver to branches to tags to... 🤷♂️and that's generally why we've leaned away from recommending that route - it's can make updates a lot crazier. that's particularly the case when, say, you have A -> B -> C and A -> D -> C, B and D don't agree on C very well, but there's some _really_ old version of B that doesn't require C at all. without constraints to guide it away from that super old version, dep will likely end up picking the very old version of B. version constraints can do a lot to help narrow the field.
that, and because we've tried to dep in such a way that your use of it for "binary" vs. "lib" projects is basically the same - we, intentionally, do not distinguish between these.
so right, the above is why we append the constraint: it's based on the observation that the version we happened to grab just now is the first version that's guaranteed to have all the things you _might_ use from that dependency. so, we stick it in
Gopkg.tomlin order to keep your project on a sane, likely-to-work path - whether that's the purpose of your owndep ensure -updates later, or if the project is being brought in as something else's dependency.