155

coming from a Node environment I used to install a specific version of a vendor lib into the project folder (node_modules) by telling npm to install that version of that lib from the package.json or even directly from the console, like so:

$ npm install express@4.0.0

Then I used to import that version of that package in my project just with:

var express = require('express');

Now, I want to do the same thing with go. How can I do that? Is it possible to install a specific version of a package? If so, using a centralized $GOPATH, how can I import one version instead of another?

I would do something like this:

$ go get github.com/wilk/uuid@0.0.1
$ go get github.com/wilk/uuid@0.0.2

But then, how can I make a difference during the import?

CinCout
  • 9,486
  • 12
  • 49
  • 67
Wilk
  • 7,873
  • 9
  • 46
  • 70
  • 4
    You don't, `go get` is not the correct tool if you want this behaviour. You can google around for solutions to your specific problem. – Wessie Jul 20 '14 at 21:54
  • 1
    Read [this](https://code.google.com/p/go-wiki/wiki/PackageManagementTools) – kostix Jul 22 '14 at 07:48
  • https://stackoverflow.com/questions/30188499/how-to-do-go-get-on-a-specific-tag-of-a-github-repository This looks helpful too – earlonrails Apr 04 '19 at 19:54
  • For Go 1.11 or higher, see Go Modules: https://stackoverflow.com/questions/53682247/how-to-point-go-module-dependency-in-go-mod-to-a-latest-commit-in-a-repo/ – Everton Oct 04 '19 at 21:03

15 Answers15

79

Go 1.11 will have a feature called go modules and you can simply add a dependency with a version. Follow these steps:

go mod init .
go mod edit -require github.com/wilk/uuid@0.0.1
go get -v -t ./...   
go build
go install 

Here's more info on that topic - https://github.com/golang/go/wiki/Modules

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
krish
  • 1,081
  • 9
  • 10
45

Really surprised nobody has mentioned gopkg.in.

gopkg.in is a service that provides a wrapper (redirect) that lets you express versions as repo urls, without actually creating repos. E.g. gopkg.in/yaml.v1 vs gopkg.in/yaml.v2, even though they both live at https://github.com/go-yaml/yaml

This isn't perfect if the author is not following proper versioning practices (by incrementing the version number when breaking backwards compatibility), but it does work with branches and tags.

Nik
  • 2,885
  • 2
  • 25
  • 25
Steven Soroka
  • 19,404
  • 4
  • 52
  • 40
  • 5
    I like (and use) gopkg, but the versioning [does not work correctly](https://github.com/niemeyer/gopkg/issues/9) with sub-packages. Just something to be aware of. – Alec Thomas Apr 05 '16 at 00:57
  • gopkg.in is not fully tested in git old versions, so it doens't work properly with git < v1.9 – BMW Dec 02 '16 at 05:20
  • Also, it only works for major versions. It's unusable to guarantee reproducible builds. – CAFxX Jun 14 '18 at 06:05
39

A little cheat sheet on module queries.

To check all existing versions: e.g. go list -m -versions github.com/gorilla/mux

  1. Specific version @v1.2.8
  2. Specific commit @c783230
  3. Specific branch @master
  4. Version prefix @v2
  5. Comparison @>=2.1.5
  6. Latest @latest

E.g. go get github.com/gorilla/mux@v1.7.4

monkrus
  • 1,470
  • 24
  • 23
28

You can use git checkout to get an specific version and build your program using this version.

Example:

export GOPATH=~/
go get github.com/whateveruser/whateverrepo
cd ~/src/github.com/whateveruser/whateverrepo
git tag -l
# supose tag v0.0.2 is correct version
git checkout tags/v0.0.2
go run whateverpackage/main.go
João Paraná
  • 1,031
  • 1
  • 9
  • 18
19

Nowadays you can just use go get for it. You can fetch your dependency by the version tag, branch or even the commit.

go get github.com/someone/some_module@master
go get github.com/someone/some_module@v1.1.0
go get github.com/someone/some_module@commit_hash

more details here - How to point Go module dependency in go.mod to a latest commit in a repo?

Go get will also install the binary, like it says in the documentation -

Get downloads the packages named by the import paths, along with their dependencies. It then installs the named packages, like 'go install'.

(from https://golang.org/cmd/go/)

homiak
  • 401
  • 5
  • 12
16

Glide is a really elegant package management for Go especially if you come from Node's npm or Rust's cargo.

It behaves closely to Godep's new vendor feature in 1.6 but is way more easier. Your dependencies and versions are "locked" inside your projectdir/vendor directory without relying on GOPATH.

Install with brew (OS X)

$ brew install glide

Init the glide.yaml file (akin to package.json). This also grabs the existing imported packages in your project from GOPATH and copy then to the project's vendor/ directory.

$ glide init

Get new packages

$ glide get vcs/namespace/package

Update and lock the packages' versions. This creates glide.lock file in your project directory to lock the versions.

$ glide up

I tried glide and been happily using it for my current project.

Pandemonium
  • 7,724
  • 3
  • 32
  • 51
  • 1
    For completeness, here is the website for glide: https://glide.sh/ And here the repo: https://github.com/Masterminds/glide – Michael Franzl Jun 26 '16 at 20:14
  • unfortunately Glide is not "active" anymore, on the github page they suggest to migrate to the official packages management (now go modules) – damoiser May 24 '19 at 09:14
14

Update 18-11-23: From Go 1.11 mod is official experiment. Please see @krish answer.
Update 19-01-01: From Go 1.12 mod is still official experiment. Starting in Go 1.13, module mode will be the default for all development.
Update 19-10-17: From Go 1.13 mod is official package manager.

https://blog.golang.org/using-go-modules

Old answer:

You can set version by offical dep

dep ensure --add github.com/gorilla/websocket@1.2.0
Baptiste Mille-Mathias
  • 2,144
  • 4
  • 31
  • 37
vitams
  • 585
  • 6
  • 7
11

From Go 1.5 there's the "vendor experiment" that helps you manage dependencies. As of Go 1.6 this is no longer an experiment. Theres also some other options on the Go wiki..

Edit: as mentioned in this answer gopkg.in is a good option for pinning github-depdencies pre-1.5.

Community
  • 1
  • 1
larsmoa
  • 12,604
  • 8
  • 62
  • 85
10

dep is the official experiment for dependency management for Go language. It requires Go 1.8 or newer to compile.

To start managing dependencies using dep, run the following command from your project's root directory:

dep init

After execution two files will be generated: Gopkg.toml ("manifest"), Gopkg.lock and necessary packages will be downloaded into vendor directory.

Let's assume that you have the project which uses github.com/gorilla/websocket package. dep will generate following files:

Gopkg.toml

# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
#   name = "github.com/user/project"
#   version = "1.0.0"
#
# [[constraint]]
#   name = "github.com/user/project2"
#   branch = "dev"
#   source = "github.com/myfork/project2"
#
# [[override]]
#  name = "github.com/x/y"
#  version = "2.4.0"


[[constraint]]
  name = "github.com/gorilla/websocket"
  version = "1.2.0"

Gopkg.lock

# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.


[[projects]]
  name = "github.com/gorilla/websocket"
  packages = ["."]
  revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
  version = "v1.2.0"

[solve-meta]
  analyzer-name = "dep"
  analyzer-version = 1
  inputs-digest = "941e8dbe52e16e8a7dff4068b7ba53ae69a5748b29fbf2bcb5df3a063ac52261"
  solver-name = "gps-cdcl"
  solver-version = 1

There are commands which help you to update/delete/etc packages, please find more info on official github repo of dep (dependency management tool for Go).

Aliaksei Maniuk
  • 1,534
  • 2
  • 18
  • 30
  • 1
    Dep was an official experiment to implement a package manager for Go. As of 2020, Dep is deprecated and archived in favor of Go modules, which have had official support since Go 1.11. For more details, see https://golang.org/ref/mod. – Aliaksei Maniuk Jan 11 '22 at 02:40
4

go get is the Go package manager. It works in a completely decentralized way and how package discovery still possible without a central package hosting repository.

Besides locating and downloading packages, the other big role of a package manager is handling multiple versions of the same package. Go takes the most minimal and pragmatic approach of any package manager. There is no such thing as multiple versions of a Go package.

go get always pulls from the HEAD of the default branch in the repository. Always. This has two important implications:

  1. As a package author, you must adhere to the stable HEAD philosophy. Your default branch must always be the stable, released version of your package. You must do work in feature branches and only merge when ready to release.

  2. New major versions of your package must have their own repository. Put simply, each major version of your package (following semantic versioning) would have its own repository and thus its own import path.

    e.g. github.com/jpoehls/gophermail-v1 and github.com/jpoehls/gophermail-v2.

As someone building an application in Go, the above philosophy really doesn't have a downside. Every import path is a stable API. There are no version numbers to worry about. Awesome!

For more details : http://zduck.com/2014/go-and-package-versioning/

Community
  • 1
  • 1
faisal_kk
  • 1,039
  • 1
  • 11
  • 19
  • 2
    As a complementary comment: if you need a specific version of a 3rd party package (other than `HEAD`), you can clone it to a git repo of your own and refer to the clone in your code. – ivotron Aug 10 '15 at 21:27
  • 46
    Your statements about the functionality of go tools are correct, but nearly nobody incorporates versions into their git repository names, and many people do not treat master/HEAD as a stable API. I currently have a small service with about eight dependencies; only one has a version number. Amazon pushed a breaking change to github.com/aws/aws-sdk-go. `go get`'s caching means you don't notice for a while unless you have a build server that's helpfully updating you to the latest version each time. There are third party package managers, but they are mostly crud. – dhasenan Nov 03 '15 at 18:30
  • 19
    @faisal_kk you must be living in a dream world. In the REAL world of the wonderful open-source community, everybody is adhering to their own philosophy. There is no such thing of branching releases, I'm glad we have tags. –  Apr 04 '16 at 08:23
  • 29
    Create a repository for every version? It is crazy – deFreitas Jun 12 '16 at 00:38
  • 8
    This is fundamentally wrong behavior. Source code is NOT the same as a released package, and you can not put on package authors to ensure backwards/forward compatibility. Not because developers are incompetent, but because this is theoretically impossible when number of package dependencies increase beyond one. Go get is therefore destined to go the same way as bower, whose main flaw was this exact same one. Semantic versioning is not strong enough either, binary checksums are really the only way to go. – Gudlaugur Egilsson Nov 22 '16 at 13:13
  • 2
    "Every import path is a stable API. There are no version numbers to worry about. Awesome!" This sounds so naive. – neuro_sys Feb 03 '17 at 11:42
  • 2
    Absolutely misunderstunding of power of git and github. Downvoting. – x'ES May 17 '17 at 17:44
  • 5
    "There are no version numbers to worry about. Awesome!" That has to be the most absurd statement in an SO answer ever. Versioning is there for a reason. Go's lack of a package manager which has an inbuilt configuration or command oriented mechanism for versionning of dependencies per say does not imply that versionning is a nuisance. Downvoting! – Harindaka Dec 01 '17 at 11:35
3

The approach I've found workable is git's submodule system. Using that you can submodule in a given version of the code and upgrading/downgrading is explicit and recorded - never haphazard.

The folder structure I've taken with this is:

+ myproject
++ src
+++ myproject
+++ github.com
++++ submoduled_project of some kind.
buckaroo1177125
  • 1,555
  • 11
  • 22
3

That worked for me

GO111MODULE=on go get -u github.com/segmentio/aws-okta@v0.22.1

Vadym Tyemirov
  • 8,288
  • 4
  • 42
  • 38
2

There's a go edit -replace command to append a specific commit (even from another forked repository) on top of the current version of a package. What's cool about this option, is that you don't need to know the exact pseudo version beforehand, just the commit hash id.

For example, I'm using the stable version of package "github.com/onsi/ginkgo v1.8.0".

Now I want - without modifying this line of required package in go.mod - to append a patch from my fork, on top of the ginkgo version:

$ GO111MODULE="on"  go mod edit -replace=github.com/onsi/ginkgo=github.com/manosnoam/ginkgo@d6423c2

After the first time you build or test your module, GO will try to pull the new version, and then generate the "replace" line with the correct pseudo version. For example in my case, it will add on the bottom of go.mod:

replace github.com/onsi/ginkgo => github.com/manosnoam/ginkgo v0.0.0-20190902135631-1995eead7451

Noam Manos
  • 15,216
  • 3
  • 86
  • 85
1

The current way to do this is to use go install

https://golang.org/doc/go-get-install-deprecation

Starting in Go 1.17, installing executables with go get is deprecated. go install may be used instead.

go install github.com/someone/some_module

Specific version

go install github.com/someone/some_module@v1.1.0

Specific commit

go install github.com/someone/some_module@commit_hash
SomeGuyOnAComputer
  • 5,414
  • 6
  • 40
  • 72
0

It might be useful.

Just type this into your command prompt while cd your/package/src/

go get github.com/go-gl/mathgl@v1.0.0

You get specific revision of package in question right into your source code, ready to use in import statement.

blacha
  • 93
  • 2
  • 7