Use git to restore parts of a file

The restoration movement
The git logo with the 'git restore --patch' superimposed next to it.

One of my favorite, little-known git tricks is using the --patch option (-p for short) to affect only parts of a file when you're adding, committing, or---as I recently found out---/restoring/.

Now some of you may be thinking 'hold up! Restoring a file? What's that?' If you haven't been following git development for a while (while a solid project, it's not exactly the JS framework du jour), you'd be excused for not knowing about the two new git commands switch and restore. Introduced in git 2.23.0 (released in August 2019), these two commands were introduced to offload the checkout command for switching branches and restoring files. As you may expect, switch allows you to switch branches (and create new ones in the same way as checkout -b by using switch -c), and restore takes over for restoring files from a previous commit.

git restore -p

While there is lots to be said about the new commands and all the options they accept, I advise you to go check out the official docs for ~switch~ and ~restore~ for that. This post is about using restore with the -p option, specifically.

Sometimes (read: quite often) when making changes to a file, you have some changes that you want to keep and some that you want to discard. In situations like this, there's a number of ways to go about it. If the changes are ready to be staged or committed, you can use the -p option to pick the parts you want and then just restore the file afterwards. However, in the event that the changes you want aren't quite ready just yet, and you don't want to stage, restore, and unstage, you might want to consider using restore -p.

By default, restore -p brings up an interactive prompt that lists the differences between your working tree and the last commit, asking you in turn whether you want to discard each hunk. This way, if you have some changes in one part of the file that you don't want to keep, you can discard those, but keep the rest. As per usual with the --patch option, you can also split hunks or edit them manually if you need to.

When not given any paths to act on, git restore -p will ask you about all your unstaged changes in all your files. To limit it to a specific file, supply a pathspec: git restore -p myfile.txt. The documentation says that '--patch can accept no pathspec and will prompt to restore all modified paths.'[1], but when testing it out using git version 2.23.1, using pathspecs was no problem at all.

In addition to the default patch restoration functionality, some of the other notable options are:

~-s <tree>~ / ~--source=<tree>~
Use this option if you want to restore a file to a different commit than HEAD. What you pick as your source can be another branch, a commit hash, or something like HEAD~2. Without the --patch flag, this will change the entire file to reflect the state at that source.
~-S~ / ~--staged~
Not to be confused with the lowercase -s above, the -S option allows you to restore changes from the index (your staging area or 'added files'). By default, restore only works on files in your work tree. Using this option will make it work only on files in your staging area. To act on both at once, supply both the -S and the -W (--worktree) options: git restore -SW.

Footnotes

[1]https://git-scm.com/docs/git-restore#Documentation/git-restore.txt---patch



Thomas Heartman is a developer, writer, speaker, and one of those odd people who enjoy lifting heavy things and putting them back down again. Preferably with others. Doing his best to gain and share as much knowledge as possible.