DEV Community

Matija Krajnik
Matija Krajnik

Posted on • Originally published at letscode.blog

Go modules and private GIT repositories

Some time ago i stumbled upon an issue that was giving me a headache. I had to download and import private Go module, and as it turns out, that can be little tricky. I'm using SSH keys for authenticating with my repositories, so this solution is applied only for that type of authentication.
Of course, i scouted internet looking for solutions, and there are some examples you can find, but none was working for me. Until i realized that there is small but crucial difference depending on which Git repository hosting service you are using. I will show you how to do it for GitHub and Bitbucket. Of course, all examples here are using URLs to my private repositories, and you will have to change them to match yours.

I prepared two simple private repositories for this little demo. Both are essentially the same. They have one package named hello with function World() returning string Hello World!. They are located on:

  • GitHub - github.com/matijakrajnik/goprivatemodule
  • Bitbucket - bitbucket.org/matijakrajnik/goprivatebucket

Now, if i tried simply running go get like below, that will not work.

go get github.com/matijakrajnik/goprivatemodule
go get bitbucket.org/matijakrajnik/goprivatebucket
Enter fullscreen mode Exit fullscreen mode

First thing i had to do is set GOPRIVATE environment variable. This variable contains a list of module path prefixes that are considered to be private, so go will not use proxy nor trying to validate checksum from public database.

To set that variable, run:

go env -w GOPRIVATE=github.com/matijakrajnik/goprivatemodule
Enter fullscreen mode Exit fullscreen mode

It's also possible to use glob pattern to match all of your repositories:

go env -w GOPRIVATE=github.com/matijakrajnik/*
Enter fullscreen mode Exit fullscreen mode

And even make comma separated list to include multiple values:

go env -w GOPRIVATE=github.com/matijakrajnik/*,bitbucket.org/matijakrajnik/*
Enter fullscreen mode Exit fullscreen mode

Setting GOPRIVATE variable is only first step. When you run go get command, Go uses git for downloading module source files. And by default, git uses HTTPS, which will not work because terminal prompts are disabled and git don't have any credentials for authentication. So you will end up will error like this:

$ go get -v github.com/matijakrajnik/goprivatemodule
go get: module github.com/matijakrajnik/goprivatemodule: git ls-remote -q origin in /home/matija/go/pkg/mod/cache/vcs/f53d9a18ffd3065378124236da32538eaf1adb1addf29c1ac217b2540997b252: exit status 128:
        fatal: could not read Username for 'https://github.com': terminal prompts disabled
Confirm the import path was entered correctly.
If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.
Enter fullscreen mode Exit fullscreen mode

Fortunately, if you are using SSH keys for authentication, solution is very simple. You just need to configure git to use git instead of https.

For GitHub repository use:

git config --global url."git@github.com:matijakrajnik/goprivatemodule.git".insteadOf "https://github.com/matijakrajnik/goprivatemodule"
Enter fullscreen mode Exit fullscreen mode

For Bitbucket repository use:

git config --global url."git@bitbucket.org:matijakrajnik/goprivatebucket".insteadOf "https://bitbucket.org/matijakrajnik/goprivatebucket"
Enter fullscreen mode Exit fullscreen mode

If you look carefully at these two commands above, you can see that subtle little difference i mentioned at the beginning. Notice that in GitHub URL you have to include .git suffix, while for Bitbucket you can't use it. This can also vary from one git service implementation to another, so if you have problem, try to add or remove that .git suffix.

You can check git configuration file located in ~/.gitconfig, to check that commands above took effect. If everything is ok, you will see something like this:

[url "git@github.com:matijakrajnik/goprivatemodule.git"]
  insteadOf = https://github.com/matijakrajnik/goprivatemodule
[url "git@bitbucket.org:matijakrajnik/goprivatebucket"]
  insteadOf = https://bitbucket.org/matijakrajnik/goprivatebucket
Enter fullscreen mode Exit fullscreen mode

With that setup i was able to download my private modules with:

go get github.com/matijakrajnik/goprivatemodule
go get bitbucket.org/matijakrajnik/goprivatebucket
Enter fullscreen mode Exit fullscreen mode

And use them in my project:

package main

import (
  "fmt"

  "github.com/matijakrajnik/goprivatemodule/hello"
)

func main() {
  fmt.Println(hello.World())
}
Enter fullscreen mode Exit fullscreen mode
package main

import (
  "fmt"

  "bitbucket.org/matijakrajnik/goprivatebucket/hello"
)

func main() {
  fmt.Println(hello.World())
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)