If you work with git, especially with either GitHub or CodePlex, you’ll commonly need to merge from branches in a different fork into your own branches in your own fork.
A typical scenario is you’ve forked a repo, made some changes, and now you want to send a pull request to get your changes into the original repo. Of course, not many people will accept your pull request unless you first merge their latest changes into your code – it’s only polite, after all!
At first this can seem daunting but, once you’ve done it a few times, it’ll become second nature.
The method I’m going to show you isn’t necessarily the quickest or most efficient under all circumstances but it’s reliable and, most importantly, if you make a mistake you won’t lose any work. When you use git (or any scm) sooner or later you’ll screw something up. Everybody does: don’t worry about it. If you’ve taken precautions, it won’t matter, so you should feel free to experiment and learn. In the worst case you can always blow away your local repo and do a fresh clone from your remote.
Anyway, back to our merge. There are three stages to the process:
- Prepare so that if something goes wrong (it shouldn’t) you can get your local repo back into a consistent state.
- Merge changes from the branch on the other fork into your local branch.
- Push those changes to your fork’s remote branch (optional).
I’ve broken the first two stages down into quite a few steps, but don’t worry: they’re all simple, and the whole process really doesn’t take very long. Like I say, it’ll quickly become second nature.
The purpose of this is to ensure that, if anything goes wrong, you can get back to a repository in a consistent state without losing any of your own changes.
- If necessary, switch to the branch you want to merge into (make sure you’ve committed or stashed any changes on your current branch first!) with:
git checkout <branch_name>
- Firstly, check if you have any local changes. Make sure you’re in a folder somewhere in your local repo and execute:
This will tell you about any changed, new, or deleted files.
- Now stage any modified files for commit (you can obviously skip this step if there aren’t any):
git add <path_to_file_1> <path_to_file_2> ...
You can also use wildcards:
git add *.cs *.js
BE CAREFUL with this. You can inadvertently add a lot more than you intend! If that does happen you can unstage any erroneously staged files with:
git reset HEAD <path_to_file_1> <path_to_file_2> ...
If you’ve accidently added loads of files you’ll probably find it easier to use the same wildcards to unstage the lot, before adding the right files individually:
git reset HEAD *.cs *.js
Don’t worry: you WILL NOT lose uncommitted changes: you’ll just change the status of these files from staged back to modified/added/deleted.
- Commit your changes locally with:
git commit -m "Write your commit message here."
- Pull any changes from your own remote:
- Manually merge any conflicts that git couldn’t auto-merge. I use Scooter Software’s Beyond Compare for this, but you can use whatever tool you like. I used to be a fan of WinMerge but have recently run into problems with it. YMMV.
- Build your code, and fix any errors.
- Run your tests, and fix any failures.
- Commit any changes you’ve made locally again (git status, git add …, git commit -m …).
- If you’ve had to spend much time on the last four steps: pull, build, and run tests again (fix any problems and commit your changes again, obviously).
- Push changes to your remote repo:
All your changes are now safe and, if something goes wrong, you can just clone again from your remote repo with:
git clone <remote_repo_name>
If you don’t want to push changes to your remote repo you can just create a copy of your local repo in a separate folder using Windows Explorer, or from the command line. You can of course try to fix your local repo using git commands but, unless you’re very experienced, there’s a good chance you’ll make matters worse. If you’ve created a backup this doesn’t matter: go ahead and use git to try to fix any problems so that you’ll become more competent with it and, if it doesn’t work, just rename your banjaxxed repo folder and copy your backup back into place. If you don’t have time to mess around just do the rename and copy.
This is where the fun begins.
- First we need to add the other fork as a remote for your repo.
git remote add <remote_name> <fork_url>
<remote_name> is just the identifier you will use when referring to the remote – essentially it saves you from having to type out the entire fork URL each time. For example, ms11022014.
<fork_url>, as you may have guessed, is the URL for the fork’s repo, e.g., https://git01.codeplex.com/forks/bartread/ms11022014.
- Now verify the remote using:
git remote -v
You should see some output similar to this, with both a fetch and a push line for your new remote:
ms11022014 https://git01.codeplex.com/forks/bartread/ms11022014 (fetch) ms11022014 https://git01.codeplex.com/forks/bartread/ms11022014 (push) origin https://git01.codeplex.com/forks/bartread/rgnpm01 (fetch) origin https://git01.codeplex.com/forks/bartread/rgnpm01 (push)
- Fetch the branches and commits of the new remote with:
git fetch <remote_name>
- If needs be, switch to the branch you want to merge into, with:
git checkout <branch_name>
- Merge changes from the required remote branch:
git merge <remote_name>/<remote_branch_name>
For example, to merge from the above remote’s master, I’d execute:
git merge ms11022014/master
- Check git’s output for conflicts and manually resolve any you need to, as in Prepare step 6.
- Build your code, run tests, and fix any errors/failures, as in Prepare steps 7 and 8.
- Commit any changes to your local repo with git status, git add …, and git commit -m …, as in Prepare steps 2, 3, and 4.
If you’ve got this far the hard part is over: you’ve merged changes from a branch in the remote fork into one of your own local branches, and committed them to your local repo.
That might be all you need to do at this point. If you do need to push changes back to your own remote fork (most likely, origin), just execute:
git push <remote_name> <branch_name>
So, to push changes from master back to origin, I’d execute:
git push origin master
And you’re done!
Help! It’s all gone horribly wrong! What do I do?
If you followed my advice in the prepare stage you can just “restore from backup” (if you didn’t, I’m afraid you’re on your own):
- Rename your local repo directory.
- Either clone your remote repo again (use git clone <remote_repo_url> from the command line), or copy (don’t move!) the backup of your local repo that you created in a separate folder back into its original location.
- Verify that your cloned or copied repo is in a good state (e.g., build your code, run tests).
- Delete the old local repo directory that you renamed.
Now you can try again.