git add -p won't split
It is amazing how many developers I run into that don't seem to either know
about git add -p
(a.k.a. git add patch), and ever fewer that know what to do
when git add -p
won't let you split your hunks up any further. Given how much
I use this command in my workflow to facilitate creating logically chunked,
buildable commits I figured I might as well make a post just touching on it.
Yes, this is something that less keyboard driven developers often ignore as
they use a GUI (ex: Sublime Merge) to stage things at a smaller
granularity. To be completely honest I use Sublime Merge to stage changes
myself sometimes. However, there are a large number of times where I am already
working on the command line with Git and therefore it is quicker and easier
just to stay on the keyboard and use git add -p
.
So lets break things down a bit.
git add
git add
is a command that allows you to take local changes and move them to
the staging area in preparation for making a commit. The idea is that you move
all the changes you want in your commit into the staging area and then turn the
changes in the staging area into your commit.
git add -p
When git add
is executed with the -p
option it instructs git add
to allow
you to select a portion of the changes in a local file for staging rather than
the entire set of changes in that local file.
Lets look at an example to see exactly how this works.
For sake of discussion lets say we have the following local, unstaged changes.
❯ git diff
diff --git a/README b/README
index d325bcb..f8f8d46 100644
--- a/README
+++ b/README
@@ -5,3 +5,9 @@ Subtitle of README
Description of the README
First paragraph of the README
+
+Second paragraph
+
+Third paragraph
+
+Fourth paragraph
Given that we are following best practices because we want all the awesome Git commands to be able to work on our repo and we want our Git history to be useful we decide we want to create three separate commits, one to add each of the paragraphs in the diff.
To do this we first start out by running the following:
git add -p README
This prompts us with:
❯ git add -p README
diff --git a/README b/README
index d325bcb..f8f8d46 100644
--- a/README
+++ b/README
@@ -5,3 +5,9 @@ Subtitle of README
Description of the README
First paragraph of the README
+
+Second paragraph
+
+Third paragraph
+
+Fourth paragraph
(1/1) Stage this hunk [y,n,q,a,d,e,?]?
Oh No! Where is s?
Most of the time when you run git add -p
it will present s
as one of the
choices in the output. s
stands for split and tells git add -p
to split the
currently presented hunk into smaller hunks and then ask you if you want to
stage the smaller hunks.
But in this case and generally when you get your hunks small enough it won't split them any further. At this point you have use one of the other options it provides.
Woot woot, e here we come!
The e
option stands for edit and it puts us into manual hunk edit mode in our
editor. This looks like the following.
# Manual hunk edit mode -- see bottom for a quick guide.
@@ -5,3 +5,9 @@ Subtitle of README
Description of the README
First paragraph of the README
+
+Second paragraph
+
+Third paragraph
+
+Fourth paragraph
# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging.
# If it does not apply cleanly, you will be given an opportunity to
# edit again. If all lines of the hunk are removed, then the edit is
# aborted and the hunk is left unchanged.
As we can see from the comments we can simply delete the '+' lines we don't want in this hunk. So in this case I edit the hunk to look as follows and save and quit the editor.
@@ -5,3 +5,9 @@ Subtitle of README
Description of the README
First paragraph of the README
+
+Second paragraph
If we run git status
we can see it resulted in part of the changes be staged
and the other part not. Lets verify the parts are as we expect.
❯ git diff --staged
diff --git a/README b/README
index d325bcb..8f6f97e 100644
--- a/README
+++ b/README
@@ -5,3 +5,5 @@ Subtitle of README
Description of the README
First paragraph of the README
+
+Second paragraph
The staged changes are correct.
❯ git diff
diff --git a/README b/README
index 8f6f97e..f8f8d46 100644
--- a/README
+++ b/README
@@ -7,3 +7,7 @@ Description of the README
First paragraph of the README
Second paragraph
+
+Third paragraph
+
+Fourth paragraph
And the unstaged changes are correct.
So now we can make our first commit, git commit -m "first commit"
.
From here we can simply rinse and repeat the process to end up with isolated logically chunked commits.