git transfusion

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 remote add origin 
github:yourgithubusername/yournewremoterepo
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 add github 
github:yourgithubusername/yournewremoterepo
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

# Add back the origin
git remote rename origin bitbucket
git remote add origin github:yourgithubusername/yourgithubrepo

# 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:"]
    insteadOf = "github:" ↩︎

  3. Note that for the step where branches are tracked from a remote branch, I modified a snippet I found here. ↩︎

  4. I love to quote this saying (as readers of my blog are aware from previous posts). For those of you who haven't read this before, the quote doesn't originate with David. While the exact origins of the quote are unknown, but it's been attributed to the Sufi Sage Mulla Nasrudin, Jim Horning, and Frederick P. Brooks. ↩︎