The typical way of undoing an ongoing work is often… a good ol' Ctrl-Z in our editor, but that can prove to be long and fastidious, or downright impossible if we already closed the files we want to undo edits on.

In that scenario, git checkout comes to the rescue so we can “cancel” changes inside our working copy and, if we had staged this already, we can even restore the relevant index parts.

A quick aside here about this double-dash notation in commands before paths. This is a common syntax that is not Git-specific but more of a command-line-related convention that signals the end of options, so the program knows anything that follows are actual path names, and not potential options.  This is useful to help Git disambiguate between, say, references such as branch names and actual file paths. Don't let that distract you, but know that when no ambiguity exists, this double dash isn't necessary. I personally only use it when I do need to disambiguate.

OK, back to checkout: the critical thing to know is that checkout doesn't really cancel edits but rather overwrites files, as this command takes a source state from our Git database and replicates it in our working copy. By default, the source state is the index, which means only the working copy is impacted. Otherwise, when we specify a source revision we want to grab state from, we impact both the index and the working copy. This is exactly what happens when we “switch branch,” by the way, but that’s another story…

Again I want to stress that checkout overwrites our current working copy of the paths we list. This is one of the very few scenarios where you can lose work, as Git hasn’t recorded the ongoing changes to these paths yet. So be advised: you won’t be able to get these “pending changes” back!

Let's look at what's going on when we change a file we already committed. Its Git state appears as modified, highlighted here in green. We can roll back to the previous state by asking Git to copy the latest known version of this file in the index for the working copy. To do so, we use the command git checkout -- my-file. Look at what this does: the version of the file is copied from the index to the working copy.

Let's try that in the terminal.

(Example 01-undo-wd-changes)

So here’s a project with 4 modified files file-1, file-2 and in the sub-dir, file-3 and file-4. If we try a git status we can see Git displays a rather clear message: “use "git checkout -- <file>..." to discard changes in working directory)”. Remember that when you’re lost or unsure, git status remains your best ally.

If we follow these instructions and do a git checkout -- file-2 sub-dir/file-3, then try another git status, we’ll see that files 2 and 3 were overwritten so they don’t show up as modified anymore. Sometimes Git notifies us about the overwrite with a message such as “2 paths updated from the index”.