TL;DR: gb does not use the
GOVENDOREXPERIMENT, vendored code goes in
GOVENDOREXPERIMENT flag, which is enabled by default in Go 1.6, allows go gettable code to include some or all of its dependencies in a
vendor/ folder at the top of its repository.
GOVENDOREXPERIMENT flag has no effect on gb.
gb does not use
go get to retrieve dependencies, and gb projects are not go gettable.
You can vendor dependencies (via
gb vendor fetch or manually) that themselves include a
vendor/ folder, but gb will ignore them for the purposes of dependency resolution.
To resolve these ignored dependencies, you can either copy them from each dependency’s
vendor/ folder to the top level of your
$PROJECT/vendor/src directory, or vendor a fresh copy with
gb vendor fetch.
The latter is the recommended process so the dependencies’ location is recorded in the gb vendor manifest file.
Irrespective of the way you choose to build up your
$PROJECT/vendor/src folder, the responsibility of deciding which copy of a particular dependency’s source to use falls to you, the project owner.
Building or testing with the race detector requires that your Go installation have a current version of the race enabled runtime and standard library. If not, gb will exit with an error like this:
% gb build -race FATAL: go installation at /Users/dfc/go is missing race support. See https://getgb.io/faq/missing-race-support
To solve this error, you need to install
If you have installed Go from the https://golang.org/ website, your operating system’s distribution, or some mechanism other than compiling Go from source, then you should not receive this error. All Go distributions from https://golang.org/ come with the race runtime properly built. If gb says that your Go installation is missing race support, your Go install may be incorrectly installed.
I strongly recommend using the official binary distributions from https://golang.org/, they are very well tested and known to work.
If you have compiled Go from source using
./all.bash (or the Windows equiv.), the race enabled runtime will not be built.
To build the race enabled runtime and standard library, run the following command:
go install -a -race std
DO NOT RUN THIS COMMAND IF YOU HAVE NOT BUILT GO FROM SOURCE
gb is only concerned with building code inside your project, how gets there and how that code is updated, is not
With that said, the
gb-vendor plugin can help fetch and manage vendored code.
Go code is organised into packages. Every package has a name, which is derived from its
package declaration, and an import path which is derived from its relative location inside
$PROJECT/src (or inside
As an example the file
a.go containing the declaration
package a inside the directory
$PROJECT/src/github.com/dfc/a has the name
a, and the import path
There exists an ambiguity if Go code is placed directly at the root of the project’s source directory, e.g.,
$PROJECT/src/a.go. In this case the package’s name is
a, but the package’s import path is blank, as its directory name is the same as the project’s source directory,
It is not possible to use a package with a blank import path:
import "" is a syntax error. A blank import path gives rise to two problems.
gb always works in terms of package import paths, a package with a blank import path—that is a package whose source is stored in
$PROJECT/src—is invisible when using the globbing operators like
gb build all and
gb build github.com/....
gb a relative path to the package—i.e.,
gb build . or
gb build ..—to explicitly tell
gb to build the source in a particular location (and infer the import path later) will result in an error.
% pwd /home/dfc/devel/demo3/src/a % gb build .. # build the package directly above this directory FATAL command “build” failed: “/home/dfc/devel/demo3/src” is not a package
To avoid this situation, we recommend that all Go code inside
gb projects be placed in subdirectories of
Some systems with the git plugin for
oh-my-zsh installed include an alias
git branch. This conflicts with
If you see this error running
% gb fatal: Not a git repository (or any of the parent directories): .git % which gb gb: aliased to git branch
You can remove the alias with
% unalias gbSee also issue #4
The short answer is yes: you can vendor source from one
gb project to another—just copy the code from your
$PROJECT/src/ into the downstream project.
Vendoring dependencies is similar; you’ll need to merge the contents of your libraries
$PROJECT/vendor/src/ into the downstream’s vendor directory.
gb cannot help you with this, as Go projects don’t have any concept of versions; there is no way you can look at the source of a Go package and ask it “What version are you?”
Now you might have commit hashes for both copies of a particular package you are vendoring, and you might be able to take those commit hashes and look them up in the source repository and say, “Hash
abced is newer than hash
Ultimately this is down to the project owner—the one consuming the code—and not the library developer—the one producing the code—to solve.
Additionally, if your organisation is happy to use tools like Git submodules or Git subtrees, then this can make it easier for the downstream project to at least know which revision of a vendored dependency it is dealing with.
gb does not mandate the use of Git subtrees or submodules; all it cares about is that the source is present inside
gb is agnostic to the source control system you use to manage your project. If your source control system has a concept of linking different repositories together, a la, git submodules or svn externals, then you can use that rather than copying code.
The Go authors agree that vendoring, taking a copy of your dependencies, is the path to repeatable builds – we just disagree on the method.
The Go authors are recommending vendoring by copying the source of your dependencies into a folder inside your package, then rewriting the source of those vendored dependencies to accommodate.
gb also recommends vendoring, but with its project based approach, it can give the same result – all dependencies are bundled within the project, without rewriting the source code. This is important, and I believe other Go programmers agree.
gb is a project based tool. Every subcommand works on a list of import paths (packages) within that project, and most default to “all packages in the project”.
One of my frustrations with the go tool was its inconsistency in this manner, most go commands work on import paths, except for
go run which takes a file. Actually that’s not correct,
go run takes a list of files, but your chances of success of using it drops exponentially the more files you pass to
While I recognise the utility of
go run for simple examples, and it’s a great way to introduce the language, the fact that it works allowed many new gophers to use it well past the point of its original intent and have a confusing and unsatisfactory time. When they ask for help, they have the double wammy that smug experienced gophers tell them “they are holding it wrong” and should learn to restructure their code.
gb is focused on a project workflow, not a package or file workflow; most of the time you are building or testing your project (see digression in #49 ) I felt I could make things simpler and more consistent by not supporting
gb run at all.
I think the fact that
gb does not just wrap the go tool is one if its distinguishing features.
Technically there is nothing that
gb does that couldn’t be done with a shell script. In fact, several tools have been proposed over the last few years that do just this, with the exception of Keith Rarik’s
godep, all have been completely overlooked by the market.
Why is this? Well probably for one, Go programmers want to use tools written in Go. This seems like a bizarre statement, but it’s true, not just for Go programmers, but pretty much most programming communities.
The second reason is, while you can construct an equivalent line of shell script to mimick what
gb does, generalising that shell script with $PROJECT detection from your working directory and then handling the case where you may be several levels deep inside the $PROJECT is difficult. What could have been a one line shell script now becomes a rather complicated shell script, which adds further weight to programmers not wanting to use a tool not written in their language. Then let’s talk about Windows compatibility …
I think there is also value in convention. I chose vendor/src arbitrarily because that’s what it was called in Rails. Without this convention people would use 3pp, external, etc. Everyone would come up with their own naming convention, and suddenly you’re not talking one shell script, but one shell script per project, along with various configuration flags, etc.
So, what does
gb do? Nothing that you couldn’t do by hand. But people don’t want to do things by hand, hence
Thanks for the feedback.