Skip to main content

Staging different parts of the same file with Git

Posted in Development and Git

I used to love the way I could chunk down a commit with Tower by looking at a file that has changed and clicking the lines that I wanted to add to staging. Since leaving Tower behind and moving to command line only for Git, I’ve missed that feature a lot.

I know git add has a --patch flag, and I’ve tried it once or twice, but every time I did, it felt a bit complicated and overwhelming, so I put it off.

Instead, I found a couple of work arounds:

  1. Only change the lines of code that belong to the commit I’m going to make
  2. Change multiple lines of code that belong to two (or more) commits, delete the code that belongs to commit number 2, make commit number 1, undo the deletion, make commit number 1

The first might actually be Git best practice, but it means I don’t always remember what I was going to do in the next commit by the time I get to it.

The second is just plain old messy. One false move and I’ve lost the ‘redo’ history.

So in order to mitigate forgetfulness or disorder, I thought it was time to make a concerted effort to learn how to use patch mode. That way I can over-code if I want to, then stage only specific chunks (or “hunks”) of what I’ve changed for one commit, leaving the rest for the subsequent commit(s).

Choosing a file

To open up the patch mode, you need to first tell Git what file you want to have a look through:

git add -p path/to/file.html

Or you could cycle through every changed file by leaving out the file name/path:

git add -p

You could use the more explicit --patch flag instead of -p, but I like to keep it brief.

Inside the file

This will then open up patch mode, which is a bit like when you’re diffing a file, but with just the first hunk of changed code in view, followed by a bunch of options, and this is where I’ve always given up:

Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,s,e,?]?

See what I mean about overwhelming?

Things get even more dizzying if you type ? and hit Return:

y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

But what if I told you that you only really need a couple of those options?

Start with a couple and build from there

The two options that you should hone in on to start with are pretty obvious:

  1. ‘yes’ (y)
  2. ‘no’ (n)

The only other command that might come in useful is s, which is used to split a hunk down further.

So you move through the hunks of code with y and n, and if a hunk is too big, using s should be enough to then carry on with y and n.

As you get used to these options, you could make things more efficient by experimenting with a, d and some of the others. I’m yet to brave some of them (like e), but will write about them when I do.

Back to the command prompt

Once every hunk in the file has been reviewed, you land back on the command prompt, outside of patch mode. A quick git status will show that the file you’ve just gone through and staged parts of is both added and not added to the staging area, which is what we’d expect.

Follow it all up with a git commit -m "This is my commit message" and that’s it!

Git’s patch mode looks daunting but can be learned bit by bit, starting with the basic options and building from there.

Accessibility in your inbox

I send an accessibility-centric newsletter on the last day of every month, containing:

  • A roundup of the articles I’ve posted
  • A hot pick from my archives
  • Some interesting posts from around the web

I don’t collect any data on when, where or if people open the emails I send them. Your email will only be used to send you newsletters and will never be passed on. You can unsubscribe at any time.

More posts

Here are a couple more posts for you to enjoy. If that’s not enough, have a look at the full list.

  1. Upgrading from iPhone 13 mini to 16 Pro

    I get a new phone every 3-ish years, give mine to my wife, and now she gives hers to our daughter. I got a 16 Pro this year! Here’s the skinny.

  2. Apple, you’re doing the Dynamic Island wrong

    I love the idea of Dynamic Island; making lemons into lemonade and all that. But, in my opinion, Apple have got the fundamentals mixed up.