loading...
Cover image for Working with forks in Go

Working with forks in Go

loderunner profile image Charles Francoise Updated on ・3 min read

Proper use of forks

Dinglehopper me on GitHub

Have you ever wanted to create a fork of a Go package you're using? Maybe you need to add a feature, specific to your use case, and there is no other way than to change it inside the code. Or maybe you want to fix a bug and submit a PR to an open-source project.

Whatever the case, Go, with its location-based import system, makes it hard to swap implementations of a package. If you try to just swap it into place, you'll most likely get an error along the lines of: cannot use s (type "fork".SomeStruct) as type "original".SomeStruct in argument to SomeFunc as soon as you pass your data types to a function defined in another file.

You can fix this with heavy refactoring — changing imports in your own code, and typecasting everything coming in from or going out to another package — but it's near impossible on a large project with many files.

Type aliases can help, but with a little bit of Git magic, you can seamlessly swap a package for your fork and keep hacking away.

Fork and fix

Not like that, no

I won't go into detail on how to create a fork and submit a PR, GitHub has extensive documentation on the subject. I'll just assume you've clicked the "Fork" button on GitHub, and now have your own repository containing a duplicate of the original source.

But as we've said, you can't just go get the forked repository, since all the import paths will be wrong. What we want is to have your local branch, inside your GOPATH, track your forked remote repository, instead of the original.

Let's start by adding a remote. From the package source path, type the following:

$ git remote add forked <remote repository url>

Then, let's make sure the local branch tracks the forked remote, and not the origin any more.

$ git branch -u forked/master
Branch master set up to track remote branch master from forked.

After this line, you can start committing and pushing to your own fork, and all Go packages relying on this repo will transparently use your own fork of the code.

This is useful, for example, if you're sure of a bugfix, as you can start working with the fixed version of the code without waiting for the changes to be merged upstream.

When you want to revert to tracking the origin, perhaps because your PR has been merged and you have deleted your fork, or because you need to use the original code for some other project, just type:

$ git branch -u origin/master
Branch master set up to track remote branch master from origin.

# Reset local branch to remote HEAD
$ git reset --hard origin/master

With these few lines of git, I can quickly fork and work on an open-source Go package. It's made my collaboration on open-source projects that much easier. What is your workflow for collaborating on open-source Go projects? Do you see any mistakes or caveats? Feel free to comment below!

Discussion

markdown guide
 

Nice approach! This also works fine for me if the package is not something to be imported by another package (i.e. a final product):

$ cd $GOPATH/src/github.com/username
$ git clone https://github.com/username/repo && cd repo
$ git remote add upstream https://github.com/original/repo
$ cd .. && cd .. && mkdir original
$ mv username/repo original/repo
 

Thanks for your solution. I had to fetch before setting the upstream branch.

git fetch --all