At work we have been using GitLab for a while and it’s been pretty good but we have recently opted to move to GitHub Enterprise. As a result there are a number of small repos we have hosted on GitLab that now need to be moved over to GitHub.
Additionally, this should generically work for any git repository migration but I’m explicitly calling out “gitlab” and “github” in hopes it makes the post easier to follow — and because it’s my actual use case.
The process is as follows:
- Mirror clone the old repo @ GitLab
- Mirror push to the new repo @ GitHub with pre-commit hooks skipped
- Update the push URL for the mirror cloned repo
Why clone as `mirror`?
Because it’s like `–bare` but with more magic!
This blurb from the git docs pretty much covers it:
Set up a mirror of the source repository. This implies –bare. Compared to –bare, –mirror not only maps local branches of the source to local branches of the target, it maps all refs (including remote-tracking branches, notes etc.) and sets up a refspec configuration such that all these refs are overwritten by a git remote update in the target repository.
And from GitHub’s docs:
As with a bare clone, a mirrored clone includes all remote branches and tags, but all local references will be overwritten each time you fetch, so it will always be the same as the original repository.
Why skip pre-commit hooks?
You may not need to do this but the repos I’ve been working on have a lot of pre-commit stuff that runs — tests, static analysis, etc. For the purpose of just pushing the entire repo to a new location i don’t care about this stuff. `–no-verify` tells git to push and skip the hooks.
Repo Migration Process
Developer Change Process
For developers who are using the repos being migrated, the process for pointing @ GitHub is a one liner.
Sometimes you accidentally commit code under the wrong author or committer credentials. This has happened to me a few times while writing code from computers with global git settings. By using `git filter-branch` it is possible to rewrite history… muhahahah!
This snippet will run through your branch’s historical commits and rename the author and committer attributes.
It basically looks for all commits containing a given `$OLD_EMAIL` and resets the following properties:
This code is an updated version of the “nuclear option” code provided in the ProGit book.
Finally just push:
git push --force --tags origin 'refs/heads/*'
Have you ever had this happen to you?
- You finish writing some awesome code. You’re a bad ass and you know it.
- You hit the command line, because you stopped creating GUI interfaces using visual basic a long time ago.
- Issue a little “git add” here and there, add some broth, a potato. Baby, you’ve got a stew going… So you commit!
- You do the habitual post-commit “git status” for no good reason and there it is, the file you friggen forgot to add to the commit you already committed to.
Fortunately git has a really convenient way to amend to your last commit! Just simply stage the file(s) you missed and run:
git commit --amend
Some notes on thee specifics of merging vs rebasing with Git.
What is a Merge?
When you merge one branch into another branch the branch being merged into receives a single commit that basically brings it up to the current state of the source branch.
This commit is created automatically by git and essentially represents all of the differences between the branches stuffed into one change. If you were to `git log` in the branch that was merged into, you wouldn’t see any of the commits that had been made in the source branch.
What is a Rebase?
With rebase you basically say “use another branch as new base for my work”. Behind the scenes what appears to be happening is that git takes the current branch and rewinds any updates you have made on it. It then moves the starting point to the head of the branch you’re rebasing against. Finally all of the rewound changes are then applied on TOP of the updated/new starting point.
One thing to keep in mind with rebasing is that it will rewrite commits. Senko’s blog post explains it pretty poignantly:
In rebase, you change your branch (that’s being rebased) so it looks like it was branched off a new base, not the original one. This involves rewriting the commits, so you’ll end up with different commit IDs.