Table of Contents
- Create new repo locally
- Process to move one repo
- Follow
- Save it all to git
- Clean up old remotes and delete repos
- Final clean up
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.
TLDR:
- Create new repo (or use existing)
- Add another repo as a remote
- Pull it with
--allow-unrelated-histories
flag - 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.
For beginners, I recommend getting more comfortable with git, before attempting the following steps. Checking out 19 Git Tips For Everyday Use
and Git Cheat Sheet to learn more.
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
Code language: PHP (php)
Update user name and email, if needed:
git config user.name "Some User"
git config user.email "user@somesite.com"
vim .git/config # Optional to see/check the config
Code language: PHP (php)
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
Code language: JavaScript (javascript)
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
Code language: CSS (css)
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
Follow
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
Code language: PHP (php)
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
Code language: JavaScript (javascript)
You can also re-use one of the existing repos too, you will just need a -f
flag.
Warning: 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
Code language: PHP (php)
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
Code language: PHP (php)
Hope this helped.