Update files in vendored library

Viewed 330

I need to make some changes to a file in one of the vendored libraries.

What is the best way to go about it?

Maybe:

 1. fork repo
 2. make changes
 3. update dependencies to use fork
 (4.) make pr to original repo

2 Answers

I would advise not modifying the vendor directory yourself except for temporary debugging. Instead, in general the process today would be something like the following.


  1. For the sake of simplicity, remove the existing vendor directory while you work. (You'll rebuild it later with your changes.)
$ rm -r ./vendor

  1. Clone the upstream repo (or your own fork of the upstream repo) to a local directory. (Be sure to read the upstream maintainer's license, README, and/or contributing guide so that you understand their process for testing, code review, etc.!)
$ git clone https://github.com/julian59189/somerepo

As part of this step, you may need to add a go.mod file if the upstream repo doesn't already have one.

$ pushd ./somerepo
$ go mod init example.com/somerepo
$ popd

  1. Add a replace directive to your go.mod file to point the dependency to the fork. (For more detail, see Developing and testing against unpublished module code.)
$ go mod edit -replace example.com/somerepo@someversion=./somerepo

  1. Make and test the change in your local clone, and push it to your fork. Record the commit hash for later use.
…
$ go test ./... example.com/somerepo/...
$ pushd ./somerepo
$ git commit -a
$ COMMIT=$(git rev-parse HEAD)
$ git push
$ popd

  1. Send an upstream PR for the change, following the upstream author's instructions.

  1. (optional) If you expect the PR to take a while to be merged, at this point you may want to update the replace directive to point to the published fork instead of the local clone.
$ go mod edit -replace example.com/somerepo@someversion=github.com/julian59189/somerepo@$COMMIT
$ go mod tidy

Now anyone who checks out your repo and works within your module will use the fixed version, even if they re-run go mod vendor (for example, to pick up an unrelated fix in a different module).


  1. (optional) Rebuild your local vendor directory, if you use one, with the replacement in effect, and commit the changes. At this point, your own module itself is fixed, but nobody who uses your module will see the fix (because you are not the authoritative owner of the upstream module).
$ go mod vendor
$ git add go.mod go.sum vendor
$ git commit

  1. Once the upstream PR is merged, drop your replace directive and update to the latest upstream. (If the upstream author hasn't tagged a release yet, you can use a pseudo-version by passing a specific commit hash to go get instead of latest; see Getting a specific commit using a repository identifier.)
$ go mod edit -dropreplace=example.com/somerepo@someversion
$ go get -d example.com/somerepo@latest
$ go mod tidy
$ go mod vendor  # If you want to keep a vendor directory going forward.
$ git add go.mod go.sum vendor
$ git commit

Regardless of the license, from a pragmatic point of view it depends a lot on the circumstances.

  • If it is a critical bug affecting your production -> modifying vendor is probably the fastest way but the main drawback is that the fix should be cherry-picked each time the library is updated.
  • If is a nice to have thing or is not compromised in your backlog -> PR will benefit your project and also the community. Moreover, updating a version would be as easy as change it on the go.mod file.
  • Forking is the long path of modifying vendor, it has all drawbacks and one more: maintain an extra repository.

In any case, avoid license restrictions with FREE software LIBRE is quite important.

Related