A Git + Drupal Primer
Now that the Drupal community's migration to Git is in full swing, it's a great time to switch your own projects as well. Curious? Perhaps you saw the Git panel in San Francisco, or maybe you've listened to Sam Boyer campaigning passionately at your local DrupalCamp. Is there a rebel in your office who keeps going on about how much better life can be with git-svn? (How ironic that Subversion is now the establishment.)
If you're just getting started, here are some tips I've collected over the last year. Or if you're already a Git ninja, here's how you can help.
Tune your environment
A few tweaks to your shell environment and Git config can make Git even more awesome.
Set up your shell
With a few lines in your ~/.bash_profile, you can get auto-completion of Git commands and branches, as well as the repository status in your command prompt.
source /opt/local/share/doc/git-core/contrib/completion/git-completion.bash GIT_PS1_SHOWDIRTYSTATE=true export PS1='[\u@mb \w$(__git_ps1)]\$ '
These paths are for Git installed via macports, yours may differ.
Set an editor
Your editor of choice will be used for writing commit messages, as well as some of Git's interactive features. I use TextMate, so this command does the trick:
git config --global core.editor "mate -w"
Set a merge tool
For Mac users, the XCode developer tools include a nice graphical diff utility, FileMerge. You can set this as your merge tool with this command:
git config --global merge.tool opendiff
FileMerge is also a great patch review tool, but that's a topic for another post.
GitX (screenshot above) is an awesome history browser for OS X. Enough said.
When disaster strikes
Inevitably, you'll make some blunders as you explore some of Git's more advanced features. Here are some ways to recover.
Undo a commit with Git revert
Unlike other VCSs I have used, git-revert actually does what you want. Simply run
git revert <commit>
and a new commit will be added that reverses the change you specified.
Start over with Git reset
If all hope has been lost, you can usually reset back to your last commit with:
git reset --hard HEAD
You can also reset to a specific commit, but note this causes commits that are forward of your reset point to be lost (assuming they don't still exist in another branch or remote).
Use local topic branches for scary changes
If you're attempting something unfamiliar (say rewriting history with an interactive rebase), I have found that doing this work in a branch makes it easy to recover if you screw up: Just checkout master again, and delete the experimental branch. If the result of your endeavor needs to eventually be the master branch, you can always delete master and re-create it as a fork of your topic branch.
Rewriting history is dangerous
Speaking of rewriting history, it's dangerous. It's just like a bad time-travel movie, where every attempt to fix the past just makes things worse, though eventually you'll probably figure it out (and win the girl). In the end, you'll learn a valuable lesson never to do that again. Of course, just like in the sequel, the power of time traveling is addictive and you'll keep coming back for more anyway.
Working with Git
Mine your history with Git pickaxe
Let say you want to trace the lineage of the mysterious
$conf['page_cache_fastpath']. You could use git-blame, but that only shows the most recent change. With
git log -S, you can see all commits with diffs that contain your search string. Add a
-p to see the actual diffs.
Use the index
Git has an intermediate storage area between your local repo and working copy, known as the index. You'll also sometimes see this referred to as the stage, or the cache. As far as I can tell these are all the same thing (corrections are welcome if anyone can explain the subtleties of these terms).
You can selectively commit only parts of a file with
git add -p or
git add -i. To compare what's in the index with your latest HEAD, run
git diff --cached.
Format a patch for drupal.org
When you need to export a patch for drupal.org, make sure to use the
--no-prefix option. I usually have a topic branch for each issue I'm working on, so to make a patch I would run
git diff master --no-prefix. If there are uncommitted changes in your working directory that you don't want in the patch, you can temporarily move them out of the way with git-stash.