Re: [go-nuts] How to pin go dependencies to a specific git commit?

2,447 views
Skip to first unread message

Jesse McNelis

unread,
May 10, 2013, 2:25:21 AM5/10/13
to Traun Leyden, golang-nuts
On Fri, May 10, 2013 at 4:16 AM, Traun Leyden <traun....@gmail.com> wrote:

My go app has a dependency on the foo library (hosted on github), but the latest commit of foo is broken, so I need to declare that I want to depend on an earlier commit.  

'go get' doesn't offer anyway to do this. But you can easily do it manually by going to the package's directory and run the necessary git commands to checkout the commit you want to use.

If the latest version of 'foo' is broken then it's probably a good idea to file a bug report, and send a fix to the maintainer of the package. It's better to have stable APIs than depending on specific versions.


 

In general, I want to be able to pin dependencies to certain commits (similar to the way Gemfile.lock with Rails/Bundler works)

Is there any way to do that w/ Go?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
=====================
http://jessta.id.au

Henrik Johansson

unread,
May 10, 2013, 2:51:09 AM5/10/13
to Jesse McNelis, golang-nuts, Traun Leyden

I generally agree with the Go team view on dependencies but as a simple help it would be very beneficial to be able to supply a tag commit id in the import. It is not meant as a solution to the dependencies problem but rather as a way to get somewhat repeatable builds in a world where a stable master branch is at best an ideal.

Traun Leyden

unread,
May 10, 2013, 2:54:32 AM5/10/13
to Jesse McNelis, golang-nuts
Fair enough, but what about this scenario?

1. I write my code against foo version 123, and it works.

2. The maintainer of the foo library pushes version 124, which breaks compatibility with my code.

3. My colleague checks out my code and runs "go get", pulling foo version 124, and things are in a totally broken state.  

4. I have to stop what I'm doing in order to fix things, which may be non-trivial fixes, and in the meantime my colleague is totally blocked.

If the go dependencies offered a way to specify a particular commit, all this would be avoided.  And for people who always want to stay at the bleeding edge of every dependency, they could just leave that parameter off and they'll always get the latest.  

Jan Mercl

unread,
May 10, 2013, 2:55:33 AM5/10/13
to Henrik Johansson, Jesse McNelis, golang-nuts, Traun Leyden
On Fri, May 10, 2013 at 8:51 AM, Henrik Johansson <dahan...@gmail.com> wrote:
> I generally agree with the Go team view on dependencies but as a simple help
> it would be very beneficial to be able to supply a tag commit id in the
> import. It is not meant as a solution to the dependencies problem but rather
> as a way to get somewhat repeatable builds in a world where a stable master
> branch is at best an ideal.

Better just forget it as it doesn't actually help in the general case.
If there happens to be required (transitively) two different versions
of the same package in one program - you're doomed.

-j

Henrik Johansson

unread,
May 10, 2013, 3:03:09 AM5/10/13
to Jan Mercl, golang-nuts, Traun Leyden, Jesse McNelis

Yes I know but I would be fine with the build failing at that point.
Now I clone important deps and maintain them in a stable state as best I can which sort of works but can be a little bit of in some cases.

Sean Russell

unread,
May 10, 2013, 6:32:24 AM5/10/13
to golan...@googlegroups.com, Jesse McNelis, traun....@gmail.com
+1 on this.  It is especially odious when it's a tool that does exactly what it was intended to.  Because of this inability to pin to a version, it now has a much higher maintenance cost that it wouldn't otherwise have.  It also means that organizations/people can't have guaranteed reproducible builds with the official Go build tools.

I feel your pain.  There are three solutions that I've thought of:
  1. Fork every project you use, recursively, suffer through the tedium and annoyance of renaming all of every dependency's import paths, and only ever depend on your own forks.  This is the only solution that works well in a team environment.
  2. Build your projects in a VM or container, and never update the dependencies once you get it working.  Share this image with your co-workers.
  3. Make files that leverage GOPATH and manually check out dependencies and update clones to specific versions.  This is probably more long-time effort than #1 because of the recursive dependency issue.
go get is awesome, but some way of specifying versions is needed.  Either a package/dependency metadata file, or through the import metadata. Import metadata would be cleaner, but if it is optional information then you're still going to have problems with ancestor dependencies at some point. The most robust solution is some sort of snapshot tool that follows the entire dependency graph at some point and records the rev #s, and then a build tool that makes use of that to make sure the versions are correct right at build time. Without this, #1 is really the only option that doesn't rely on building some custom build framework.

--- SER

Jan Mercl

unread,
May 10, 2013, 6:49:38 AM5/10/13
to Sean Russell, golang-nuts, Jesse McNelis, traun....@gmail.com
On Fri, May 10, 2013 at 12:32 PM, Sean Russell <seaner...@gmail.com> wrote:
> Fork every project you use, recursively, suffer through the tedium and
> annoyance of renaming all of every dependency's import paths, and only ever
> depend on your own forks. This is the only solution that works well in a
> team environment.

The result of 'go get' already is a "local fork" (actually a clone) of
the remote repository. The go tool never updates this clone until
explicitly told so. So there's no need to rename any import paths and
yet you can have a stable foreign repository (clone) version. How to
mount and/or make such repository available to the whole team is
another question - outside of this topic scope, but for sure easy in
several different ways.

-j

Damian Gryski

unread,
May 10, 2013, 7:14:36 AM5/10/13
to golan...@googlegroups.com, Jesse McNelis, traun....@gmail.com

Keith Rarick has some preliminary ideas, but no code yet: https://github.com/kr/godep

Damian

André Moraes

unread,
May 10, 2013, 9:27:02 AM5/10/13
to Traun Leyden, golan...@googlegroups.com
The Go way is:

If a package will change in some way that old cold will stop working,
they author of the package should:

* Create the new package under a different path (this is simple, just
add a new folder and do the changes there)

* Write a gofix to change the code

* Find another way to do it

The stdlib follow this pratice, most people follow this pratice.

If you already are in a situation where the package is broken, just
fix your code or use another package.

--
André Moraes
http://amoraes.info

Henrik Johansson

unread,
May 10, 2013, 10:14:10 AM5/10/13
to André Moraes, golang-nuts, Traun Leyden

I like this way! However it remains to be seen if the disciplin and practise of this way of working is upheld. I think my stuff is safe since i rely only on dependencies created by long time go users.

Ryan Leavengood

unread,
May 10, 2013, 10:49:51 AM5/10/13
to golan...@googlegroups.com, André Moraes, Traun Leyden
On Friday, May 10, 2013 10:14:10 AM UTC-4, Henrik Johansson wrote:

I like this way! However it remains to be seen if the disciplin and practise of this way of working is upheld. I think my stuff is safe since i rely only on dependencies created by long time go users.

If a library creator doesn't have the discipline to follow proper release practices and the idioms in the Go community, I think it can be argued that you probably don't want to be using their code in production either.

It is trivial to maintain a release/master and develop branch with distributed source control systems, and if someone releases a library which other people use, it becomes part of their responsibility to maintain compatibility as much as possible.

While this discussion sounds good in theory, I think it is trying to solve a problem which is caused by bad developers.

I'm a Ruby developer learning Go and the Bundler example is not a good one, since Bundler is a tool that was required due to some bad design in the RubyGems system and bad library maintenance by Ruby developers. We've gotten used to it and therefore have forgotten what a terrible hack it is.

Regards,
Ryan

Ugorji Nwoke

unread,
May 10, 2013, 10:51:42 AM5/10/13
to golan...@googlegroups.com, Traun Leyden
I'm not sure this is the Go way.

I think this is the current practice of some package providers because "go get" doesn't support tags except for go versions e.g. go1. IMO, in hindsight, this ends up solving a problem that most people do not have, since Go versions end up being pretty compatible. 

Using a different folder really doesn't work for in a version controlled system, since the new folder loses all the source history. 

I've been fighting with this personally, and have not updated my msgpack-go library because I'm struggling with this. 

I have some ideas to help here, but am aware that this is not the best time to socialize it (sometime after Go 1.1 is out will be better).

Sean Russell

unread,
May 10, 2013, 10:11:47 PM5/10/13
to golan...@googlegroups.com, Sean Russell, Jesse McNelis, traun....@gmail.com
On Friday, May 10, 2013 6:49:38 AM UTC-4, Jan Mercl wrote:
The result of 'go get' already is a "local fork" (actually a clone) of
the remote repository. The go tool never updates this clone until
explicitly told so. So there's no need to rename any import paths and
yet you can have a stable foreign repository (clone) version. How to
mount and/or make such repository available to the whole team is
another question - outside of this topic scope, but for sure easy in
several different ways.

You've missed the issue of team development, where devs may come on the project at different points in time, and the point about repeatable builds.  I can build something at home, go in to work and try to build it there and it can fail because an upstream dependency broke API compatibility in between.  It's not uncommon with Go.

--- SER

Sean Russell

unread,
May 10, 2013, 10:19:05 PM5/10/13
to golan...@googlegroups.com, Jesse McNelis, traun....@gmail.com
On Friday, May 10, 2013 7:14:36 AM UTC-4, Damian Gryski wrote:
Keith Rarick has some preliminary ideas, but no code yet: https://github.com/kr/godep

Perfect, thanks! Keith is thinking along the same lines.

--- SER

Rory McGuire

unread,
May 14, 2013, 10:54:55 AM5/14/13
to golan...@googlegroups.com, traun....@gmail.com
check out https://github.com/divoxx/goproj.

If your project relies on other third party libraries using goproj you just create a .goproj directory at the root of the projects directory structure and use goproj instead of go i.e: `goproj get ...`


On Thursday, 9 May 2013 20:16:19 UTC+2, Traun Leyden wrote:

My go app has a dependency on the foo library (hosted on github), but the latest commit of foo is broken, so I need to declare that I want to depend on an earlier commit.  

Sean Russell

unread,
May 14, 2013, 8:00:18 PM5/14/13
to golan...@googlegroups.com, traun....@gmail.com
Thanks for this.  It doesn't quite satisfy the OP ask.  The use case is using Go in a corporate environment.  Maybe you have a team of 12 developers.  Maybe you're bringing on a new developer.  Maybe you're just trying to have repeatable, reliable builds of a version of the product.  In any case, you will, at some point, need to build the app in an environment in which it has never before been built.  Most teams want to tightly control the versions of software they use, to reduce the number of variables in testing.  Having dependencies always pulled from the dependency's tip is trying to build software on constantly shifting sands.  It isn't a huge problem when you're the only person working on a project; it's a much greater concern when you're trying to collaborate.

--- SER

Rory McGuire

unread,
May 15, 2013, 1:29:34 AM5/15/13
to Sean Russell, golan...@googlegroups.com, traun....@gmail.com
okay. I just shared it because if the whole team use the same project folder there will be no problems with versions because go get doesn't update unless you specifically ask it to. and in that case you make manually break almost any project in any language.

If you are the only person on the project then the only thing goproj would solve is different version dependencies for different projects.

:) ideally I'd just want all programmers to use master for complete versions with tags to denote different versions and tip for the dev tip. :) don't see that happening any time soon.

Rory McGuire
ClearFormat - Research and Development
UK : 44 870 224 0424
USA : 1 877 842 6286
RSA : 27 21 466 9400
Email: rmcg...@clearformat.com
Website: www.clearformat.com

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/P4DXddX2fbY/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages