简体   繁体   中英

How to declare golang dependency versions best in go.mod?

The classical way to declare a dependency's version in go mod is via

require (
    k8s.io/api v0.17.4
    k8s.io/apimachinery v0.17.4
    k8s.io/cli-runtime v0.17.0
    k8s.io/client-go v0.17.4
)

In the past (go <= 1.12?) this has been resolved to timestamp versions, but recently the versions are kept untouched.

However, I've also seen this technique to pin versions:

require (
    k8s.io/api v0.17.4
    k8s.io/apimachinery v0.17.4
    k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
    k8s.io/code-generator v0.18.0
    k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
)

replace (
    k8s.io/api => k8s.io/api v0.16.4
    k8s.io/client-go => k8s.io/client-go v0.16.4
    k8s.io/code-generator => k8s.io/code-generator v0.16.4
    k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf
)

The question is why would one choose one approach over the other? Is the latter required to resolve conflicting versions coming from transitive dependencies? And if so, why shouldn't one add versions only to the replace() clause from the very beginning to be precise (not only in the conflicting case)?

A replace is helpful when you want to use a particular version of a dependency in the current module:

  • You might want to use that version because it's a fork with modifications you need.

     require example.com/original v1.0.0 replace example.com/original => github.com/... v1.0.1

    (Note: you can replace v1.0.1 with master (or another branch) and it will be replaced with a pseudo-version the next time you build / test / mod tidy .)

  • You may not be able to change minor versions of this particular dependency for some reason. Perhaps it requires extra testing to verify behavior or perhaps you've tried newer versions and they don't work.

  • You might be making changes to multiple projects, or you have multiple modules in a single repo, and you want to be able to make changes across all of the modules at the same time while developing.

In order for a replace to be meaningful, you need to be depending on the module you are replacing . You add dependencies in a go.mod by using require , so you can't only use replace .

A replace is extra work to maintain and replacing everything is not necessary in general. replace should be used selectively, when necessary, like in the situations above.

Finally, adding a replace does not make the version selection more "precise." Adding the replace makes it more difficult for a dependency to update. A human will most likely need to go in and say, "Yes, we do want to upgrade this dependency," rather than let Minimum Version Selection decide when to upgrade a dependency, which could happen accidentally without a human noticing. As noted above, that could be bad for some projects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM