Different ways to use “--patch” in Git
I’ve written previously about using --patch
to interactively stage changes. But did you know that you can use --patch
(aka -p
) to similar effect with other Git commands? Let’s take a look…
Selectively stashing changes
git stash
is great for temporarily stashing changes that you want to apply later, and handily it also supports selectively stashing changes with the --patch
flag:
$ git stash --patch
diff --git a/spec/sidekiq/upload_job_spec.rb b/spec/sidekiq/upload_job_spec.rb
index b5f1d04e..e3b6227d 100644
--- a/spec/sidekiq/upload_job_spec.rb
+++ b/spec/sidekiq/upload_job_spec.rb
@@ -7,6 +7,7 @@ describe '#perform' do
context 'the application has already been uploaded' do
let(:membership_application) { create :forsa, :uploaded }
+ # Here is change one of two
it 'lets us know via Appsignal' do
allow(Appsignal).to receive(:report_error)
job.perform(membership_application.id)
(1/2) Stash this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?
Bonus git stash
tip: you can also selectively stash entire files using --
to disambiguate the command from the paths you want stashing:
$ git stash -- path/to/file.rb
Selective discarding changes from your current work tree
You can use the git restore
command to discard local changes and restore files to their last committed state. It can also be called with the --patch
flag to interactively select specific hunks to discard:
$ git restore --patch
diff --git a/spec/sidekiq/upload_job_spec.rb b/spec/sidekiq/upload_job_spec.rb
index b5f1d04e..e3b6227d 100644
--- a/spec/sidekiq/upload_job_spec.rb
+++ b/spec/sidekiq/upload_job_spec.rb
@@ -7,6 +7,7 @@ describe '#perform' do
context 'the application has already been uploaded' do
let(:membership_application) { create :forsa, :uploaded }
+ # Here is change one of two
it 'lets us know via Appsignal' do
allow(Appsignal).to receive(:report_error)
job.perform(membership_application.id)
(1/2) Discard this hunk from worktree [y,n,q,a,d,j,J,g,/,e,p,?]?
Note the different phrasing of the prompt on the last line: Here we are choosing the changes we want to discard. Be careful, this is a destructive change, and because these are unstaged and uncommitted changes git won’t be able to help you recover the changes once they’ve been discarded!
Selectively restoring changes from another branch or commit
The git restore
command also lets you restore changes from another branch or commit by specifying the --source=
flag. Combine this with the --patch
flag and you can interactively choose the specific changes to restore to your current work tree:
$ git restore --source=branch-name --patch
diff --git b/app/models/flow_definitions/neu.rb a/app/models/flow_definitions/neu.rb
index cdabfe7a..28308244 100644
--- b/app/models/flow_definitions/neu.rb
+++ a/app/models/flow_definitions/neu.rb
@@ -42,10 +42,9 @@
step 'qualified-year' do
radio :qualified_year do
- option :'2024'
- option :'2023'
- option :'2022'
- option :'2021'
+ MembershipApplication::Neu::QUALIFYING_YEARS.each do |year|
+ option :"#{year}"
+ end
divider
(1/2) Apply this hunk to index and worktree [y,n,q,a,d,j,J,g,/,e,p,?]?
I wil sometimes use this when I have a spike branch that I want to pull a subset of changes from to be tidied up and committed in my current branch.
A quick note on git restore vs checkout
You may have noticed that the last two behaviours for discarding/restoring changes are also possible using git checkout
. git restore
was introduced to Git in version 2.23 (alongside git switch
) in an effort to reduce the overloaded (and somewhat confusing) responsibilities placed on git checkout
. Whilst it doesn’t look these features will be removed from git checkout
any time soon, the more focused commands are easier to understand (and teach!), and arguably easier to use, at least assuming you don’t have years of muscle memory to overcome.