Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between "git checkout" vs. "git restore" for reverting uncommitted file changes?

Tags:

git

Say I have a git repo with a modified file named readme.txt, and I want to undo the modifications I've made and set it back to the state of the most recent commit. It seems there are two commands to do this:

git checkout -- readme.txt

and

git restore readme.txt

Is there any difference between these two commands? I've noticed that git status offers the advice "(use "git restore <file>..." to discard changes in working directory)". Is this the canonical way to undo uncommitted modifications? Are both ways equally valid and popular?

like image 419
Al Sweigart Avatar asked Apr 09 '20 21:04

Al Sweigart


People also ask

What is the difference between GIT revert and checkout?

The old git checkout command could overwrite unsaved work: if your typo turns a branch name into a file name, for instance, well, oops. git revert (I added this for completeness): this makes a new commit. The point of the new commit is to back out what someone did in some existing commit.

What is gitgit restore and what does it do?

git restore: this got split off from git checkout. Basically, this does the same thing as the various forms of git checkout and git reset that clobber files (in your working tree and/or in Git's index).

How to revert changes for a commit in Git?

Actually, git restore and git checkout commands will remove all changes made after the last commit by default or in simple words, the file will be restored as per the last commit. Now we need to say explicitly to git checkout command to revert changes for a commit.

What is the difference between GIT checkout and hard update?

--hard – The staged snapshot and the working directory are both updated to match the specified commit. The git checkout command is used to update the state of the repository to a specific point in the projects history. When passed with a branch name, it lets you switch between branches.


3 Answers

git restore is a new command that has been introduced (last summer) in Git 2.23 together with git switch. Their purposes are to simplify and separate the use cases of git checkout that does too many things.

git checkout can be used to switch branches (and also to create a new branch before switching to it). This functionality has been extracted into git switch.

git checkout can also be used to restore files to the state they were on a specified commit. This functionality has been extracted into git restore.

They can still be performed by git checkout but the new commands are easier to use and less confusing.

To summarize,

git restore readme.txt

is a new way to do what you used to do with:

git checkout -- readme.txt
like image 169
axiac Avatar answered Oct 18 '22 04:10

axiac


As stated in the docs:

or you can restore both the index and the working tree (this the same as using git-checkout1)

It's a convenient way of doing the same thing. (first version in Git 2.23)

Blog post from GitHub about highlights of Git 2.23:

Git 2.23 brings a new pair of experimental commands to the suite of existing ones: git switch and git restore. These two are meant to eventually provide a better interface for the well-known git checkout. The new commands intend to each have a clear separation, neatly divvying up what the many responsibilities of git checkout, as we’ll show below.

like image 4
kapsiR Avatar answered Oct 18 '22 04:10

kapsiR


I like the two answers on this at the time I write mine—both axiac's answer and kapsiR's, but the way I would put it is this:

  • git checkout combines too many commands into one front end. Some of these commands are "safe", in that if you have uncommitted work, they won't destroy it, and some of these are "unsafe", in that if you have uncommitted work and tell them destroy my uncommitted work, they will do that.

  • git switch implements the "safe" subset.

  • git restore implements the "unsafe" subset.

So far, there's no particular reason to favor either the old single command or the new pair of commands. But we add one more item:

  • git checkout name may execute either the unsafe one or the safe one, depending on something you might not even be thinking about!

Now, this last bullet point is fixed in the latest Git versions. Suppose you have a remote-tracking origin/dev name and you'd like to create branch dev accordingly. Normally, you could just run:

git checkout dev

Suppose, though, that your current (probably master) checkout has a directory named dev, and in that directory, you've done a bunch of work and have not yet committed it. You just now remembered: I should commit all this work I just did on the dev branch, not the master branch.

Now, there's no existing dev branch at all, but there are dev/ files. Here's what an old Git does:

sh-3.2$ git --version
git version 2.20.1
sh-3.2$ git branch -r
  origin/dev

(that is, origin/dev exists; branch dev doesn't and I'm on master here)

sh-3.2$ git status --short
 M dev/file
sh-3.2$ git diff
diff --git a/dev/file b/dev/file
index e69de29..c238a0b 100644
--- a/dev/file
+++ b/dev/file
@@ -0,0 +1 @@
+look at all this work I did

Adding that line took weeks of hard work! :-)

sh-3.2$ git checkout dev

Uh oh. Why didn't it tell me about creating a branch named dev set up to track origin/dev?

sh-3.2$ git status
On branch master
nothing to commit, working tree clean

Gah! My hard work is all gone!

The problem here is that git checkout ran the unsafe command. I might have been expecting it to use the safe one ... but it didn't.

A more modern Git (2.24.0) will tell me that git checkout dev is ambiguous, which is good: it does not just clobber my file. (I have not tested Git 2.23 itself, where the split-into-two-commands first went in.)

Anyway, using the new commands, you at least know, right as you type in the command, whether you will get the safe mode or the unsafe one. If your habits are set and you keep using git checkout, or you're concerned about the note that says that these new commands are still experimental, you can still use the old one—and it no longer just wipes out work, in the ambiguous case.

like image 4
torek Avatar answered Oct 18 '22 02:10

torek