Why Glide 0.8 Is Our Biggest Release

Dec 11 2015

The Go package management ecosystem has been missing something -- something most other language ecosystems have had for a long time. The new version of Glide brings it.

Historically, Go dependency management has shied away from a package management philosophy. Instead, two approaches have been advocated:

  1. Copy all your dependencies into your project and manually manage them.
  2. Use a tool that pins your dependencies to a particular VCS commit (e.g. a Git SHA).

(An earlier approach, "always run the most recent version" unsurprisingly seems to have fallen by the wayside.)

Until recently, Glide largely remained a tool to help with that second approach (and extend it just a bit to better accommodate developer workflow).

But we realized that we were doing it wrong. These approaches do not yield a satisfactory workflow for many (if not most) development organizations.

Scouting the Field

Glide grew out of real-world usage. Hitting the limits of tools like Godeps and GPM, we incremented our ideas, adding small workflow changes here and there. This model worked well until we hit that watershed moment when our issue queue was filled with contrasting requirements: More flexibility to specify versions, but rigid reproducibility of the build.

That was the moment when we realized that we had begun with the wrong set of assumptions. We assumed the two methods above (store it locally or pin to a particular VCS commit) were the correct options to select from.

So we paused and did something we should have done at the outset. We looked at what other languages were doing.

We read code, we asked questions, we read issue queues and tutorials and API docs. Among the core and frequent contributors, we evaluated Gems, Bundler, Mix, npm, CPAN, NuGet, Cargo, pip, Composer, PEAR/PECL, and various Java tools. We even blogged a little bit about what we were learning.

We came away with three major lessons:

  • Dependencies should be expressible using semantic versioning. And (because Go devs aren't reliable about versioning) VCS markers like branches, commits, and tags.
  • Builds must be reproducible.
  • Thevendor/ directory, added in Go 1.5, is the right place for all applications to manage their dependencies.

As we learned these lessons, we began to incrementally make changes. First, we supported GOVENDOREXPERIMENT within a day or so of Go 1.5's release. Then we added deep support for SemVer 2 semantic versioning.

But the big change is the one we've introduced in Glide 0.8: We have added a glide.lock file.

Lock It!

Previously, the glide.yaml file could be used either for the developer to specify the version ranges of various packages or a very specific set of VCS IDs. But most of us wanted both. We wanted to say "as a developer, I want to specify the version ranges my stuff depends on" while simultaneously saying, "as a release manager, I want absolute assurance of reproducible builds."

After much experimentation (including the ill-fated glide pin commands), we realized that the route that Gems/Bundler, Composer, npm, etc. was the right one. We introduced a lock file.

Now, the glide.yaml file is used for developers to track the direct dependencies of your codebase, and the glide.lock file is used to specify the exact version of all dependencies (immediate and indirect/transient) that a codebase uses.

And just in case there is any ambiguity, we intend that both should be checked into VCS.

Usage

With this new philosophy comes a slightly revised workflow.

Make locks

The glide get and glide up commands will both rebuild the glide.lock file. Use the first to add new things, and the second to update existing things (within the version boundaries you set in glide.yaml)

Use locks

The glide install command can now rebuild a project to the exact version that the lockfile specifies. And because there is no dependency/version resolution, it's blazingly fast.

So your CI/CD system should use glide install to prep the environment. Likewise, when developers first check out an existing project, glide install will get them to a known dependency state post haste.

From there, you only need to glide get or glide up when you are explicitly modifying your dependencies.

How to Write Glide Files

Given this new setup, developers only need to work with the glide.yaml file. And the dependencies specified there can just be your code's direct dependencies. (Though in all honesty we have found cases where we wanted to manage upstream dependencies, too).

And when it comes to the glide.lock file, you can stay completely hands-off. Glide manages that fully.

The March to 1.0 is ON!

The 0.8.0 release marks a huge transition for us. We feel like we've hit the last of our major planned features. From here, we're marching toward a 1.0 release.

That means that what you will see over the next months are changes to stability, speed, and code cleanliness. But the only features we'll be adding are minor administrative features.

And a fond farewell to...

The glide guess and glide pin commands have gone away, their functionality is now totally subsumed by glide up and glide get.

In the next release, glide tree will likely fade away, too. We just haven't found it to be crucial to the core functionality of Glide.

See you in the issue queue!