Once upon a time, I’ve decided to contribute to an open source project written in Go. I thought no problem, fork it, make a change then pull request. Sounds good, but it wasn’t such a smooth experience.

My first naive step was to clone my fork to a temporary directory inside my current $GOPATH:

~GOPATH/src/github.com/vbauerster
❯ git clone https://github.com/vbauerster/the_platinum_searcher

But soon I realized, that my changes are not beeing picked up, when building my fork. A little investigation revealed the reason:

~GOPATH/src/github.com/vbauerster/the_platinum_searcher gcase*
❯ go list ./...
github.com/vbauerster/the_platinum_searcher
github.com/vbauerster/the_platinum_searcher/cmd/pt

I was editing files inside ~GOPATH/src/github.com/vbauerster/the_platinum_searcher directory, for Go it is github.com/vbauerster/the_platinum_searcher package, but the source code imports original package. So all my changes were not recognized because of that. As a workaround I had to replace the original package with my fork package in the whole codebase. Thankfully it was the only one occurrence to replace.

Thinking of a better way

Temporary replacing imports is not obviously a good way, because you have to replace them back to original, when your fork is ready to go. So at first I thought cloning the fork to a temporary directory outside of my primary $GOPATH will help. But it didn’t. Moreover I had to setup new one-time $GOPATH before cloning and with my slow internet connection, wait a considerable amount of time, for all dependencies to finish to download.

Brilliant idea: push to upstream

With this method, you don’t even need to clone your fork to your machine. Let me explain step by step. First, make a fork of interested project repo. In my case:

Interested project: https://github.com/monochromegane/the_platinum_searcher

Fork project: https://github.com/vbauerster/the_platinum_searcher

Interested project should be already in your $GOPATH, if not then do go get.

Next, add you fork as remote upstream in original project directory. This will let you make changes directly in cloned (not forked) repo.

~GOPATH/src/github.com/monochromegane/the_platinum_searcher master
❯ git remote add upstream https://github.com/vbauerster/the_platinum_searcher

~GOPATH/src/github.com/monochromegane/the_platinum_searcher master
❯ git remote -v
origin  https://github.com/monochromegane/the_platinum_searcher (fetch)
origin  https://github.com/monochromegane/the_platinum_searcher (push)
upstream        https://github.com/vbauerster/the_platinum_searcher (fetch)
upstream        https://github.com/vbauerster/the_platinum_searcher (push)

Now you’re ready to make changes in upstream branch:

~GOPATH/src/github.com/monochromegane/the_platinum_searcher master
❯ git checkout -b upstream upstream/master
Branch upstream set up to track remote branch master from upstream.
Switched to a new branch 'upstream'

Note: if you get following error

fatal: 'upstream/master' is not a commit and a branch 'upstream' cannot be created from it

make sure you issue git fetch upstream command, before above step.

Now you don’t need to search and replace any import paths. When you’re done with changes, git push inside upstream branch will push into your fork master branch. After that you can make pull request on GitHub page of your fork.

Personally, I don’t like pull requesting from a fork’s master branch. Therefore, right after forking the project, I make a branch in the fork’s repo, to be able to connect that branch to upstream:

~GOPATH/src/github.com/monochromegane/the_platinum_searcher master
❯ git checkout -b gcase upstream/gcase
Branch gcase set up to track remote branch gcase from upstream.
Switched to a new branch 'gcase'

Finally after your pull request is accepted, you can safely remove upstream and all accociated branches:

~GOPATH/src/github.com/monochromegane/the_platinum_searcher master
❯ git remote remove upstream

Happy pull requesting!