Here are the steps that I too to merge multiple GitHub repos into one, while preserving all commit history. The process took about 30 minutes for 5 repos. As a result, I feel like my GitHub page is cleaner and code is actually better organized and easier to find.
- Create new repo (or use existing)
- Add another repo as a remote
- Pull it with
- Resolve merge conflicts
- Rinse and repeat
Warning: this tutorial is aimed at intermediate Git users, comfortable with resolving merge conflicts. You can and will lose data, if you make a mistake.
Create new repo locally
All the repos will be merged here.
mkdir new-repo cd new-repo/ git init vim Readme.md # Or any other dummy file, just to get git rolling. git add . git commit -m 'Init' git status -s
Update user name and email, if needed:
git config user.name "Some User" git config user.email "email@example.com" vim .git/config # Optional to see/check the config
Process to move one repo
Repeat the following steps for every repo you want to combine.
git remote add some-old-repo https://github.com/user/some-old-repo.git git pull --allow-unrelated-histories some-old-repo master git status -s
At this point, changes from that repo should be you your master branch.
Resolve conflicts and commit changes, if needed.
Regular git stuff. If you are not sure how to do it, you should probably hold off on merging repos together until you get more comfortable with git.
I did have one interesting conflict with Readme file, that just wouldn’t go away. Eventually, I figured out that I can use a force flag on it.
Warn: Do not copy paste this line. This is an optional step provided for info only.
git rm -f Readme.md
Clean up directory structure
Move files around into a sub-directory or however you want to organize things. Commit your changes when done.
Warning: Moving files around means that history will only be available using the
--follow flag. This is a regular Git behavior, even if files are moved in one repo.
mkdir some-old-repo mv Old_Folder_One/ Old_Folder_Two/ some-old-repo/ git add . git commit git status -s
As I mentioned before, history for all files should be available now via
--follow flag, if any of the files were moved. You can also change config (on per repo basis) to make the
--follow behavior automatic.
# Should see full history git log --follow some-old-repo/some-old-file.txt git config log.follow true vim .git/config # Optional to see/check the config # Now with full history, without the --follow flag git log some-old-repo/some-old-file.txt
Save it all to git
If everything looks good, it’s time to push your new combined repo to Git.
git remote add origin https://github.com/user/new-repo.git git push
You can also re-use one of the existing repos too, you will just need a
push -f will over-write the existing master branch, so make sure you will not lose any data there.
Clean up old remotes and delete repos
Now that the merge is down, there is no longer a need for old remotes to be there.
git remote -v git remote remove some-old-repo vim .git/config # All remotes can be delete from here too
I also used this opportunity to delete old (now merged) repos in Github. I felt some fear/resistance around this step, but decided to just pull the trigger on it, after double checking that all my changes made it into the new repo.
To delete a repo in Github, go to “Settings” tab and scroll to the bottom for “Delete this repository” option.
Final clean up
I did the following final sanity check, to make sure that my repo was ready to go.
# Make sure upstream branch is set up properly git branch --set-upstream-to=origin/master master # Purge old branches git fetch -p # Diff with master, should be the same already git diff origin/master # For good measure git push git pull # Run git garbage collection, just for fun git gc
Hope this helped.