Staging patches with Git add -p

Hacker News Top Tools

Summary

A tutorial on using git add -p to interactively stage hunks of changes, allowing for selective commits and cleaner version control history.

No content available
Original Article
View Cached Full Text

Cached at: 07/29/26, 09:57 PM

# Staging patches with git add Source: [https://www.simonholywell.com/post/git-add-p/](https://www.simonholywell.com/post/git-add-p/) ## Introduction If you’re not already using`git add \-p`to stage your commits then you’re missing out\. It allows you to interactively stage a file or just part of it giving you greater control over your git commit process\. ## Why should you want to do this? Here are some of the reasons why I prefer using`git add \-p`in my workflow\. Primarily, because it allows me to review my changes as I stage them and I often find mistakes this way\. By reviewing changes during staging, I catch bugs, typos, and other issues that might have slipped through during initial coding or content creation\. There is an additional benefit though; it allows me to stage only part of file\. Git, rather oddly, refers to these parts as hunks so I will use that term going forward\. This feature is really useful when you have a number changes, but you want to group them up into different commits\. Imagine you’ve made several related changes across different parts of a file\. With`git add \-p`, you can selectively stage these changes together, ensuring cleaner and more organized commits\. ## Staging part of a file Here is an example of the interface showing you the diff and then prompting you to “Stage this hunk?”\. ``` diff --git a/main.mts b/main.mts index e1132f2..8f7c279 100644 --- a/main.mts +++ b/main.mts @@ -1,2 +1,4 @@ export const add = (a, b) => a + b +export const div = (a, b) => a / b export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x)) +export const avg = (xs) => div(sum(xs), xs.length) (1/1) Stage this hunk [y,n,q,a,d,s,e,?]? ``` In its simplest form we can enter`y`to stage that diff ready for commit or`n`not to\. For this example I am not ready to commit the`avg`function, but I want to get`div`pushed up so I choose to enter`s`to split the hunk into smaller hunks\. Git then asks me this\. ``` Split into 2 hunks. @@ -1,2 +1,3 @@ export const add = (a, b) => a + b +export const div = (a, b) => a / b export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x)) (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? ``` So I enter`y`to stage that hunk for commit and git responds with the next hunk\. ``` @@ -2 +3,2 @@ export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x)) +export const avg = (xs) => div(sum(xs), xs.length) (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? ``` Remembering that I only want to commit the`div`function I then enter`q`to quit the interactive hunk staging\. After interacting with the hunk staging, I return to the command prompt\. From there, I can proceed with git commit or any other necessary commands\. ## Checking it worked If I were to run a`git status`to check the staged files I would see that the fil \(`main\.mts`\) appears in both sections; to be committed and not staged for commit\. This is because we only staged part of the file and it is what we wanted\! ``` On branch main Your branch is ahead of 'origin/main' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: main.mts Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: main.mts ``` By selectively staging only part of the file, we’ve successfully prepared a single hunk—a patch—for our upcoming commit\. ## Other options The list \(`\[y,n,q,a,d,s,e,?\]`\) of potential responses is shortened, but you can get extended information by entering`?`to get the help documentation\. Here are some response options you can use during interactive hunk staging taken from the[git documentation](https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging#_staging_patches)\. You’ll notice that there are a lot more options than in the list we saw earlier\. - `y`: stage this hunk - `n`: do not stage this hunk - `a`: stage this and all the remaining hunks in the file - `d`: do not stage this hunk nor any of the remaining 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 ## When not to use it I use`git add \-p`nearly every time I commit every working day\. There are two occasions where I don’t: 1. There is a newly created file to commit for the first time \- when a file is newly created there is no previous version to diff against of course so`git add \-p`cannot present a diff for you to approve for staging\. 2. In rare cases, when I want to commit an entire directory and am confident about its content, I usually opt for the standard approach\. However, even in such edge cases, I often find myself using git add \-p for finer control\. ## Conclusion By incorporating`git add \-p`into your workflow, you’ll streamline your git and commit process\.\. I use this technique, without exaggeration, nearly every single time I need to commit a changeset to git\. It allows me to easily review my code as I stage it for commit and control exactly what goes into each of my commits\.

Similar Articles

The Git history command deserves more attention

Hacker News Top

The article highlights the new `git history` command with `fixup`, `reword`, and `split` subcommands, which provide atomic and branch-aware editing of commit history, offering benefits similar to jj without requiring a version control switch.

git-absorb: git commit --fixup, but automatic

Lobsters Hottest

git-absorb automatically creates fixup commits for staged changes, mirroring hg absorb's functionality. It integrates with git's autosquash to streamline applying code review feedback without manual commit SHA hunting.

Accepting a messy git history

Lobsters Hottest

A blog post discussing two git workflow philosophies—commit often vs rebase carefully—and why a messy history is acceptable given resilience in larger teams, referencing GitHub's new stacked PR feature.