A longtime Subversion user recently asked me for tips on switching to Git. A sort of “top 5 commands I need to know to get going”. Having only recently mastered this beast, I gave a few more than 5 commands as I wanted to share its true power.
It’s taken me an embarrassingly long time to become comfortable with Git, but now that I have, I love it. I say that at the outset because when learning Git, you often feel like you’re wrestling with it. I want to assure you it is worth the trouble. If you ever find yourself loosing faith, take solace in a quote from this Git vs. Mercurial post:
Git is for monstrous geeks … who like to wrestle with their tools before settling into using them.
You’re not alone. I’d say it’s more like a wild stallion though – hard to tame, but rides like nothing else once you have it under your control.
Creating a Repository
Firstly, I’d suggest signing up to GitHub and creating a repo. GitHub are pretty good at giving newbies the commands and explanation for the stage you’re at. For example, when you create a new repo, GitHub will tell you exactly what to do next.
In line with the instructions given by GitHub, this my workflow for creating new repositories.
Create a repo from the current directory:
Add all my files to the local repository & commit them (as Git is distributed, you add/commit locally then push to a remote repo as needed):
git add . git commit -am 'Initial commit'
This commits all changes to the current branch of the local repo. The
m flag adds the commit message specified, in this case “Initial Commit”.
Add the remote GitHub repo and send files to it:
git remote add origin firstname.lastname@example.org:your-username/new-repo-name.git git push origin master
The first line adds a remote repo named “origin”, the standard remote name. The second says send the changes I’ve committed locally on branch master to the remote master branch of the repo named origin.
Viewing & Committing Changes
Now a few days later, I will have made changes to my files. I’m still accustomed to centralised version control though so I don’t commit every 10 minutes like I can with Git. As a result, I have a few days worth of changes to add.
Firstly, I’ll see what files have changed since my last commit, good for people with 6 second memories like myself.
Then I’ll look at specific changes in the files the status command told me had changes.
git diff filename.php git diff another-file.php
I’ve been a bad code monkey and added a few different features and bug fixes without committing the changes. I can still make atomic commits now though.
git add filename.php git commit -m 'Fixing bug with example feature.' git add another-file.php git commit -m 'Adding another widget to foobar.'
Then I’ll send my changes to GitHub.
git push origin master
Tip: the origin master part can be done automatically by editing your .git/config file in the repo’s directory.
Now, say you follow the steps above. You’ve created a GitHub repo and sent your files to it. Then you get a Pull Request from me. I made a fork of your repo and added some awesome new features, now I’d like you to include them in your version. GitHub would give you handy instructions on what to do with it and they would be something like this.
Create a new branch to put the fork’s changes until you’re sure you want to merge them:
git checkout -b thenbrent/master
The checkout command switches to a different branch. Because the thenbrent/master branch doesn’t exist yet, we use the -b flag to create it. The name thenbrent/master is arbitrary, use anything you like that reminds you of the contents of the branch.
You would now be in the new thenbrent/master branch, ready to safely get a copy of my changes without changing your main branch. There is a big difference here between SVN and Git. Branches are not stored in separate folders. You’ll feel uncomfortable sitting in the same directory about to merge changes. It feels like you’re going to mess up your main branch. Have faith in Git’s mastery of the dark arts and pull the changes.
git pull https://github.com/thenbrent/new-repo-name.git master
The pull command both fetches the changes from my remote repository and merges them with the current branch. Git’s magic should work and merge the changes smoothly. It works 90% of the time, every time. If your merge doesn’t work, Git will give you a cryptic riddle to explain how to fix it. Fortunately, Google & StackOverflow will give you an answer to this riddle.
Now before you merge my changes into your master branch, you should take a look at the changes I made.
git diff thenbrent/master master
If it all looks good? You can switch back to your master branch and merge the changes with your master branch.
git checkout master git merge thenbrent/master
That’s my workflow, at least the one balancing Git’s power with brain computable simplicity.
git log is a beautiful thing and you must add this pastie to your .bash_profile to preserve sanity when working with multiple branches.
For more in-depth info, checkout, Git Magic. It’s by far the most engaging and entertaining Git documentation I’ve found. Almost enjoyable enough to read cover-to-cover… almost.
A useful post on GitHub collaboration and for explaining the bash_profile changes I mentioned above is on the Less Everything blog.
UPDATE: a friend also pointed me to GitBox for Mac, which he said was a great app for getting into Git.