Adventures in Git (Merging)

Starting out with a new version control system is always a unique experience. Half of your time is spent crossing fingers and hoping that you didn’t just cause irreparable damage to your repository and the other half is time spent pouring over manuals and Google results to try and get just the right commands so that the worst case (hopefully) never happens.

For a little bit now, I’ve been playing with git (due to my pet project, Joind.in being moved and open sourced over on github. It’s a different sort of experience than I’m used to coming from a CVS and SVN world where there’s one server and everything you do goes through that. Git’s different in its distributed nature and it takes a bit of getting used to – some of the core concepts are a bit different since, essentially, your clone is a full copy of the repository (and is a repository all to itself). It’s a little strange and I don’t think I fully have a handle on it yet, but I’m getting (gitting? yeah, had to throw in a pun somewhere) there.

In the meantime, I came up against something today I hadn’t had to deal with on the project. Previously, the Joind.in source was on a SVN server hosted on another machine. I had some other developers working with me on it while I was over there, and most of the changes were pretty easy to integrate with few conflicts. I’ve gotten used to handling merges in SVN, but since git’s “total repo” method is a good bit different than SVN’s approach, it took a little doing to figure out how to merge in changes from a forked repository on github and integrate them back into the master. I (finally) got it to cooperate so I wanted to share the steps I took to get it working. I know this isn’t the only way to make the merge happen, and probably isn’t even a true merge, but it got the job done.

In this example I’m going to be merging changes from Lorna Mitchell’s fork of the code back into the main line.

First off, for the impatient folks in the front row, here’s the full list of commands:
[php]
mkdir lorna
cd lorna
git init
git remote add lorna git://github.com/lornajane/joind.in.git
git remote add joindin git@github.com:enygma/joind.in.git
git pull joindin master
git checkout -b lorna/master
git pull lorna master
git add path/to/file.php
git checkout master
git status
git commit -m’Merging in the changes from the fork’
git push –dry-run –repo=joindin
git push –repo=joindin
[/php]

Want a bit more? Alright – here’s the explanation for the steps above:

  • Start with an empty directory: You don’t have to do this, but it made me a bit more comfortable to keep things out of my working copy.
  • Go into the directory and make it git-controlled with the “git init”
  • Set up some aliases: This just makes things easier to refer to down the line. In this case we’re setting up aliases for the “joindin” and “lorna” repositories to point to the remote sources on github
  • Get the main line of code: Do a pull to get the master line of code from the joindin source
  • Create a branch: When you use the “checkout” command for git, you’re moving between branches. In this case, the “-b” flag tells it to make the branch too since it doesn’t exist. Our new “lorna/master” branch is created.
  • Pull in Lorna’s code: With the new branch in place, we can pull down the fork’s code and push it into the branch (the master line from her fork). This is where the fun starts. If you have conflicts that pop up, this is where you’ll see them. They’re easy to fix, though – the technique’s similar to other version control systems and you basically just delete what’s wrong.
  • Add the fixed files: There wasn’t a “resolved” command like SVN has that I could see. The only thing I saw was to “add” the files back into the commit once they’re ready to go.
  • Switch back to the master: Move back over to the master branch (of the “joindin” repo) by doing a checkout on it
  • Check your status: Use the “git status” command to see what’s going on and if there’s anything else that might need to be done before the commit.
  • Commit!: You’re ready to commit the changes to the master branch. Issue the commit and fire away. Remember, this is all local until you do the push, so if something freaks out, you can always start over.
  • Now push!: If all went well, you’re going to end up with an integrated version of your repository and you’ll be ready to push. The “git push” command also has a –dry-run option use can use if you want to check before you make the leap. The –repo option is used to defne which repo you want it applied to.

So there you go – it’s a little tricky, but not too bad once you know the steps. This was just a simple merge, so I know there’s more to it in the future, but I suppose I’ll work on that when I get there. Hopefully this helps someone out there!