Staging patches with git add 路 Simon Holywell
馃尀
Introduction<br>If you’re not already using git add -p to stage your commits then you’re missing out.<br>It allows you to interactively stage a file or just part of it giving you greater control over your git commit process.<br>Why should you want to do this?<br>Here are some of the reasons why I prefer using git add -p in my workflow.<br>Primarily, because it allows me to review my changes as I stage them and I often find mistakes this way.<br>By reviewing changes during staging, I catch bugs, typos, and other issues that might have slipped through during initial coding or content creation.<br>There is an additional benefit though; it allows me to stage only part of file.<br>Git, rather oddly, refers to these parts as hunks so I will use that term going forward.<br>This feature is really useful when you have a number changes, but you want to group them up into different commits.<br>Imagine you鈥檝e made several related changes across different parts of a file.<br>With git add -p, you can selectively stage these changes together, ensuring cleaner and more organized commits.<br>Staging part of a file<br>Here is an example of the interface showing you the diff and then prompting you to “Stage this hunk?”.<br>diff --git a/main.mts b/main.mts<br>index e1132f2..8f7c279 100644<br>--- a/main.mts<br>+++ b/main.mts<br>@@ -1,2 +1,4 @@<br>export const add = (a, b) => a + b<br>+export const div = (a, b) => a / b<br>export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x))<br>+export const avg = (xs) => div(sum(xs), xs.length)<br>(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.<br>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.<br>Git then asks me this.<br>Split into 2 hunks.<br>@@ -1,2 +1,3 @@<br>export const add = (a, b) => a + b<br>+export const div = (a, b) => a / b<br>export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x))<br>(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.<br>@@ -2 +3,2 @@<br>export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x))<br>+export const avg = (xs) => div(sum(xs), xs.length)<br>(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.<br>After interacting with the hunk staging, I return to the command prompt.<br>From there, I can proceed with git commit or any other necessary commands.<br>Checking it worked<br>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.<br>This is because we only staged part of the file and it is what we wanted!<br>On branch main<br>Your branch is ahead of 'origin/main' by 1 commit.<br>(use "git push" to publish your local commits)
Changes to be committed:<br>(use "git restore --staged ..." to unstage)<br>modified: main.mts
Changes not staged for commit:<br>(use "git add/rm ..." to update what will be committed)<br>(use "git restore ..." to discard changes in working directory)<br>modified: main.mts
By selectively staging only part of the file, we鈥檝e successfully prepared a single hunk鈥攁 patch鈥攆or our upcoming commit.<br>Other options<br>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.<br>Here are some response options you can use during interactive hunk staging taken from the git documentation.<br>You’ll notice that there are a lot more options than in the list we saw earlier.<br>y: stage this hunk<br>n: do not stage this hunk<br>a: stage this and all the remaining hunks in the file<br>d: do not stage this hunk nor any of the remaining hunks in the file<br>g: select a hunk to go to<br>/: search for a hunk matching the given regex<br>j: leave this hunk undecided, see next undecided hunk<br>J: leave this hunk undecided, see next hunk<br>k: leave this hunk undecided, see previous undecided hunk<br>K: leave this hunk undecided, see previous hunk<br>s: split the current hunk into smaller hunks<br>e: manually edit the current hunk<br>?: print help<br>When not to use it<br>I use git add -p nearly every time I commit every working day.<br>There are two occasions where I don’t:<br>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.<br>In rare cases, when I want to commit an entire directory and am confident about its content, I usually opt for the standard approach.<br>However, even in such edge cases, I often find myself using git add -p for finer control.<br>Conclusion<br>By incorporating git add -p into your workflow, you鈥檒l streamline your git and commit process..<br>I use this technique, without exaggeration, nearly every single time I need to commit a changeset to...