Okay, so a couple months back I wrote up the absolute basics of Git, git init, git add, git commit, the stuff you need just to stop emailing yourself zip files named project_final_v3_REAL.zip. A bunch of you emailed me (my inbox is not equipped for this, by the way) asking about branches next, so here we go. This one assumes you've already got Git installed and you're not scared of the terminal.
Branches are the thing that actually make Git worth using over something like Subversion, in my opinion. Not everyone agrees with me on this and that's fine, but SVN branching always felt like performing surgery with a butter knife. Git branches are cheap. Like, actually cheap, creating one doesn't copy your whole project, it just drops a new pointer onto a commit. That's it. That's the whole trick.
Making and switching branches
The basic move is:
git branch new-feature
git checkout new-feature
or the shortcut everybody actually uses:
git checkout -b new-feature
That second command creates the branch and switches you onto it in one go. I use -b probably fifteen times a day and I still fat-finger it into -B about once a week, which force-resets the branch if it already exists. Ask me how I know.
Once you're on new-feature, anything you commit lives on that branch and doesn't touch master at all. You can go wild, break stuff, commit garbage messages like "asdf fix" (we've all done it), and your main branch stays clean the whole time. This is the part that took me way too long to internalize when I started, I kept treating branches like some precious ceremonial thing instead of just... using them constantly, for every little change.
Actually merging the thing back in
When you're done and it works, switch back to master and merge:
git checkout master
git merge new-feature
If nobody else touched master while you were off in branch-land, Git does what's called a "fast-forward", it just slides the master pointer up to where your branch is, no merge commit, nothing fancy. If master did move (say a teammate pushed something), Git creates an actual merge commit that ties both histories together. Sometimes that goes smooth. Sometimes you get a conflict and Git dumps a bunch of <<<<<<< and ======= markers into your files and you have to go pick a side by hand. Nobody enjoys this part. I don't think anyone in the history of software has ever enjoyed resolving a merge conflict.
Once you've merged, clean up:
git branch -d new-feature
The lowercase -d refuses to delete a branch that hasn't been merged yet, which has saved me more than once. If you're absolutely sure you want it gone regardless, capital -D will do it, no questions asked, no safety net. Use that one carefully. Last week I -D'd a branch I thought was merged and it very much was not, and I spent about ten genuinely panicked minutes before remembering git reflog exists and pulls you back from almost anything. Worth bookmarking that command honestly, it's saved my neck twice now.
A workflow that's actually worked for me
Here's roughly what I do these days on my own projects: master stays deploy-ready at all times, always. Every feature, every bug fix, every "quick" CSS tweak that somehow takes ninety minutes, gets its own branch off master. Name them something you'll actually remember, fix-nav-dropdown, not fix1. When it's done and tested, merge back to master and delete the branch. Rinse, repeat. It sounds almost too simple to write a blog post about but I promise half the confusion people have with Git comes from not doing this and instead just committing everything straight to master and hoping for the best.
I'm intentionally not getting into git rebase here, that's a whole other post, and honestly one I need to think through more carefully myself before I try explaining it to anyone else, because half the tutorials I've read on it contradict each other on when you're supposed to use it.
One last complaint while I've got you: git branch with no arguments just lists your local branches and it is criminally easy to forget that command exists when you've got fifteen tabs open and no idea which branch you're even on anymore. Alias it to something short. I did git st for status and git br for branch ages ago and it's saved me an embarrassing amount of typing since.