The index (sometimes called the “staging area”) is, IMO, one of the most powerful aspects of Git. There are many ways of utilizing the index, ranging from not at all (git commit -a ...) to interactively staging hunks. I’d imagine most people use git add FILE to stage an entire file and aren’t aware that they can actually stage parts of a file. This is powerful for a number of reasons.

Reason 1: You can choose to leave parts of a file out of the commit

Maybe you have some printf() style debugging in there, or you have some temporary code you don’t want committed. Either way, you can use interactive staging to leave those out of a commit.

Reason 2: Code reviewing

One thing I noticed when I do interactive staging is that I end up looking at all of the code before staging it. Even if it’s a file that I’m 99% sure I want the entirety of, I’ll still go through every modified line and remind myself what it does and why it needs to be committed. This means every time I commit, I’m doing a micro-review of the code! Very rarely have things slipped through into commits that shouldn’t, and I believe this is the reason why.

Okay, but what’s the catch?

There are a couple disadvantages to using interactive rebase, especially for staging parts of a file.

Uncompiled commits

When you stage/commit parts of a file, the resulting commit wasn’t ever compiled or tested. If your project has a policy that every commit must compile, well I believe that’s an insane policy and should be changed. If you’re using this partial-staging strategy on a user/feature branch, I believe there is no issue.

The way my workflow mitigates this problem is because I never push uncompiled/untested changes. A couple commits back to back that were never compiled? Not a problem as long as after the last commit before pushing the code compiles, it’s fine. I do this so that each commit can be a small, easily reviewed unit of work within the larger context of the feature branch. I find it’s sometimes easier to look at the individual commits of a PR to determine how/why changes were made instead of looking at the whole PR diff.

git add -p is hard to use quickly

To be honest, I’ve used git add -p less than a dozen times in my life, simply because it’s too difficult to use quickly. It also doesn’t (to my knowledge) allow you to stage single lines - only hunks (which you can sometimes split into smaller hunks). My solution to this is to use git-gui. The diff view lets you highlight lines and stage/unstage them.

(You only need to highlight part of the line, not the entire thing - it won’t ever stage part of a line.)

Another bonus of using git-gui is it will warn you if you try to stage merge conflict markers.