git transfusion

Motivation: Poor Judgement (and lack of patience)

Recently, I've been working a lot with git, a version control system. My current company decided that it would be useful to switch from Bitbucket to GitHub. Given that we had a number of repositories already in Bitbucket, it became necessary to move each of these repositories from one source to another. Obviously, we wanted to keep all branches and history intact. It's not very hard to search Google and find the easiest way to accomplish this[1], but I, being of the persuasion that enjoys pain, decided to ignore this simple prerequisite and instead push on with the benefit of only my experience. I accomplished, generally, a satisfactory result, but I thought I would document for posterity both how I should have done it, and how I did do it.
The Easy Way (How I should have done it)

The easiest way to move from one repository hosting service to another is answered in this stackoverflow post. Basically, you perform the following[2]:

git clone --mirror git@bitbucket.org:yourrepository
cd yourrepository.git
git remote rename origin bitbucket
git push origin --mirror


The Hard(er) Way (How I did do it)

This is slightly more difficult, but the reason I'm posting this is because, if you did like I did, which is move the repository initially, then make a few commits against the new repository (that, of course, weren't in the old repository, since you now consider that one dead to you), and then realize that there were items that you neglected to transfer over, then this is for you.

First, move the repository over (I assume you've probably already did this step):

cd yourrepositoryworkingdir
git remote rename origin bitbucket
git remote rename github origin
git push origin master


So, now your master branch is in the new origin, but what about the other branches? Let's move them over[3]:

cd yourrepository
# Temporarily remove reference to new remote
git remote rm origin
git remote rename bitbucket origin

# Now, track all remote branches
remote=origin; for brname in git branch -r | grep $remote | grep -v master | grep -v HEAD | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'; do git checkout$brname; done

# Remove master temporarily (as that branch has already been pushed). You'll want to do this
# For any other branches you've moved over, as well.
git branch -D master

git remote rename origin bitbucket

# Push all branches
git push origin --all

# Push all tags
git push origin --tags


While this is slightly more difficult than simply doing it the "easy" way, it does give you a bit more knowledge about the inner workings of git. A colleague of mine, L. David Baron, once told me, "Good judgement comes from experience. Experience comes from exercising poor judgement."[4] I gained a modicum of experience here, but it was worth it. Hopefully, this saves you from making the same mistakes I did, and if you do make those mistakes, it gives you an easier out to correcting them than searching Google for a couple of hours to collect all the pieces of what you need to do.

Footnotes

1. A Google search reveals the easiest way to do this with its first result. ↩︎

2. Note that this, as well as other sections of this post assume you've added the following shortened github url syntax to your global git configuration (~/.gitconfig):

[url "git@github.com:"]