Git 1.5.0 introduces git-add --interactive, which lets you stage changes at a finer granularity than the file level. This is useful if you've made a number of changes in a file before you realize that they logically should go in as separate commits. It works by allowing you to pick and choose hunks of the diff to stage.
$ git add --interactive staged unstaged path 1: unchanged +26/-6 path/to/file1 2: unchanged +1/-0 some/other/file *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now>
git shows you all the files which have changes from HEAD. To pick and choose diffs, select 5 (patch) at the menu. Git prompts you to select one of the listed files by number.
Git then shows you hunks of the diff between HEAD and your working copy. For each hunk, you can choose whether or not you want to stage the hunk. For large hunks, Git will also offer to split the hunk into smaller hunks which you can stage independently. (There are other options, such as options to stage or unstage all remaining hunks.)
Once you're done, you can select 7 to quit, do git diff --cached to verify the staged changes, and do git commit as usual to commit.
Update: you can also use git-add --patch FILENAME, which skips the menu and jumps directly to the hunk selection part. I usually use this instead of git-add --interactive now and I've aliased it to gap in my shell. If you use Emacs, magit is a great extension that also supports staging and unstaging individual hunks.
Further reading: git-add documentation