A month ago we started work on a new project at Gradient, we based it on the project structure of another preexisting code base but a few weeks ago we realised that was probably a mistake, due to some shifting requirements. Since the project wasn't too far along we decided it would be sensible to move all the code to be grounded on a different internal project where it could share a lot more code.

This is not your every day "change in requirements" but we decided it would be the right move given the circumstances. Simon set to work on a new git repository to transition to the new project structure and base components. Meanwhile, I continued working on some pieces I was doing to help us keep up the pace.

Side note: While it would be possible for us to do this on different branches, there were a few other reasons we ended up going down the path of a new repository. Generally I'd advice using the same repository and opting for branches, but in this case it wasn't the right option for a number of reasons outside the scope of this post.

Today Simon finished his work on the new project structure but it was in a new repository so I had to get my changes from one repository into another, preferably without destroying anything.

There were a couple of different ways I could have approached this, the first one my mind jumped to was to generate a .patch file with git format-patch. I actually started down that route but I quickly realised it wasn't going to work because the commit hashes in the new repository were completely different as there was no shared history. I ended up simply using a second "remote" and a cherry pick.

Adding another "remote" to your local repository

For many internal projects at a company, you'll probably just have a single "remote" for your repository. This remote will typically be called the "origin" and will be where you push and pull most of your changes. If you're working with forks you might also have setup an "upstream" which corresponds to the repository you've forked from.

Add a new remote which will represent the repository you want to push the commits to, I find it helpful to name this repository the name of the project, for our purposes I'll call it "new-proj".

You can now run git fetch to pull in data from the new remote.

Getting the branch of the new remote

You should now be able to checkout a local version of any branch from the new remote new-proj. We'll checkout the master branch for ease.

git checkout -b new-proj-master --track new-proj/master

This will create a new local branch called new-proj-master which is tracking the remote master branch. You might see some pretty drastic changes to your working tree from this, that's because you've basically just checked out a new repository.

Cherry picking changes and pushing them up

Now we can simply cherry-pick commits from any other branch in our repository over to this branch and then push the changes up to the new-proj remote.

# Checkout the remote branch
$ git checkout -b new-proj-master --track new-proj/master

# Cherry pick a change
$ git cherry-pick a940dbe

# You will now have commit a940dbe on new-proj-master.
# So if we push that branch up to the new-proj remote, the commit will be on the new repository
$ git push new-proj new-proj-master

Just like that, we have now successfully cherry picked a commit from one repository to another using a remote branch and a cherry-pick.