After a new repository has been created, before a commit has been made, when files are staged, git-status suggests using git-rm to unstage files: $ git status [...] No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) [...] After a commit has been made, git-status suggests using git-restore instead: $ git status [...] Changes to be committed: (use "git restore --staged <file>..." to unstage) [...] Why is this the case?
threads / discuss / 64155
Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
Subject: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
Sorry for that. I apologise for the messed-up formatting. Let’s try that again.
—
After a new repository has been created, before a commit has been made, when files are staged, git-status suggests using git-rm to unstage files:
$ git status [...] No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
[...]After a commit has been made, git-status suggests using git-restore instead:
$ git status
[...]
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
[...]Why is this the case?
Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
Anselm Schüler <mail@anselmschueler.com> writes:
Show 7 quoted lines
> $ git status > [...] > No commits yet > > Changes to be committed: > (use "git rm --cached <file>..." to unstage) > [...]
As this is a very initial commit, any file you are including would only exist in the index and in the working tree files. The index is where you prepare the contents of the commit you are going to create, and "git rm --cached <file>" is the way to remove <file> from there without losing or clobbering the <file> in the working tree. As you do not have a commit yet, you wouldn't have anywhere to "restore" from, would you?
Show 7 quoted lines
> After a commit has been made, git-status suggests using git-restore instead: > > $ git status > [...] > Changes to be committed: > (use "git restore --staged <file>..." to unstage) > [...]
Compared to the previous situation, you do have a commit, so you can restore to the version in that commit. During the course of development that led you to this state, you may have added <file> in a commit way before the current commit, and you may have made changes to the <file> multiple times in different commits before the current commit. "git rm --cached <file>" would not be how you would go back to the version in the current commit in such a situation, as it would take you to the state _before_ you originally added that file. You would "restore" the contents in the index to that of the current commit (i.e. HEAD) to go back to the state.
So, isn't a short answer to the "why" question, "because that is what you need to do", I guess?
Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
On Tue, Sep 16, 2025 at 4:36 PM Anselm Schüler <mail@anselmschueler.com> wrote:
Show 8 quoted lines
> > After a new repository has been created, before a commit has been made, > when files are staged, git-status suggests using git-rm to unstage > files: $ git status [...] No commits yet Changes to be committed: (use > "git rm --cached <file>..." to unstage) [...] After a commit has been > made, git-status suggests using git-restore instead: $ git status [...] > Changes to be committed: (use "git restore --staged <file>..." to > unstage) [...] Why is this the case?
By following builtin/commit.c:cmd_status() to wt-status.c and searching for "rm --cached" (and then blaming), I found the following relevant commits:
- 80f537f79c (doc: promote "git restore", 2019-04-25): conversion from reset to restore - 4d4d5726ae (status: show worktree status of conflicted paths separately, 2009-08-05): introduced the is_initial check
Unfortunately the latter does not appear to describe or justify the difference.
However, a quick test of the kind
git init foo
echo a > foo/a && git -C foo add a
git -C foo restore --staged agives
fatal: could not resolve HEAD
Contrary to Junio's mail about "where to restore from," the following does work in a non-unborn repo to move "newfile" from "untracked" to "staged" and back again:
echo >newfile && git add newfile
git restore --staged newfileSo we don't need "rm --cached" to
> remove <file> > from there [the index] without losing or clobbering the <file> in the working > tree
(But the point about having nowhere to restore from stands!)
-- D. Ben Knoble
Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
"D. Ben Knoble" <ben.knoble@gmail.com> writes:
Show 12 quoted lines
> ... " the following > does work in a non-unborn repo to move "newfile" from "untracked" to > "staged" and back again: > > echo >newfile && git add newfile > git restore --staged newfile > > So we don't need "rm --cached" to > >> remove <file> >> from there [the index] without losing or clobbering the <file> in the working >> tree
Now I think about it more, I wonder if "restore --staged" is misleading and confusing to new users?
When you teach "git restore" what would you tell them?
NAME
git-restore - Restore working tree filesis how "git restore --help" starts. It is primarily a tool to let you repair messed up files in your working tree by copying out of a known good version from somewhere, be it from the index or from an existing commit.
But the instruction used to recover from unwanted "git add" to update the index with modified contents does NOT want to destroy your files in the working tree. You want to repair only the index without touching your working tree files, because you added modified contents that were not ready to be "staged". Hence "git restore" is used with "--staged" option to tell it to do what it was *not* primarily designed to do, i.e. only touch the index without doing its usual "Restore working tree files" job.
But there is a lot more appropriate command whose primary focus is about the index. "git reset <file>" would grab the contents for the <file> in HEAD and replace the index entry for <file> with it, which is exactly how you would move the "Changes to be committed" files to "Changes not staged for commit" status.
So I think use of "git restore --staged" in the instruction is wrong, and it should be replaced with "git reset" instead.
> (But the point about having nowhere to restore from stands!)
Yes, and the point about having nowhere to reset from stands for the state on an unborn branch. That one needs "rm --cached".
Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
On Wed, Sep 17, 2025 at 8:12 AM Junio C Hamano <gitster@pobox.com> wrote:
Show 46 quoted lines
> > "D. Ben Knoble" <ben.knoble@gmail.com> writes: > > > ... " the following > > does work in a non-unborn repo to move "newfile" from "untracked" to > > "staged" and back again: > > > > echo >newfile && git add newfile > > git restore --staged newfile > > > > So we don't need "rm --cached" to > > > >> remove <file> > >> from there [the index] without losing or clobbering the <file> in the working > >> tree > > Now I think about it more, I wonder if "restore --staged" is > misleading and confusing to new users? > > When you teach "git restore" what would you tell them? > > NAME > git-restore - Restore working tree files > > is how "git restore --help" starts. It is primarily a tool to let > you repair messed up files in your working tree by copying out of a > known good version from somewhere, be it from the index or from an > existing commit. > > But the instruction used to recover from unwanted "git add" to > update the index with modified contents does NOT want to destroy > your files in the working tree. You want to repair only the index > without touching your working tree files, because you added modified > contents that were not ready to be "staged". Hence "git restore" is > used with "--staged" option to tell it to do what it was *not* > primarily designed to do, i.e. only touch the index without doing > its usual "Restore working tree files" job. > > But there is a lot more appropriate command whose primary focus is > about the index. "git reset <file>" would grab the contents for the > <file> in HEAD and replace the index entry for <file> with it, which > is exactly how you would move the "Changes to be committed" files to > "Changes not staged for commit" status. > > So I think use of "git restore --staged" in the instruction is > wrong, and it should be replaced with "git reset" instead.
As we have in git(1)
Reset, restore and revert
There are three commands with similar names: git reset, git restore and
git revert. • git-revert(1) is about making a new commit that reverts the changes
made by other commits. • git-restore(1) is about restoring files in the working tree from
either the index or another commit. This command does not update your
branch. The command can also be used to restore files in the index
from another commit. • git-reset(1) is about updating your branch, moving the tip in order
to add or remove commits from the branch. This operation changes the
commit history. git reset can also be used to restore the index, overlapping with git
restore.that already mentions the overlap, I'm inclined to keep "restore --staged" as a simpler "I'm _restoring_ this file in the index to a different version." (But my personal "unstage" alias has been "reset HEAD --" for a long time…) The Examples in git-restore(1) also mention the reset connection.
> > (But the point about having nowhere to restore from stands!) > > Yes, and the point about having nowhere to reset from stands for the > state on an unborn branch. That one needs "rm --cached".
Perhaps more germane to Anselm—I'm still confused that "restore --staged" can't cope with unborn branches. Sure, there's no "place to restore from." But the user experience of having 2 different commands depending on this one state is a bit messy, I think. Wouldn't it be nice if one command did the right thing (kicking a newly-added file out of the staging area back to being untracked) in all situations?
IOW, I think "rm --cached" works whether unborn or not—so shouldn't "restore --staged", too? As I think I saw in a separate reply, plenty of commands treat the unborn branch as having an empty tree as the parent. It seems that if "restore --staged" did so, we could unify the help here and simplify things for the user.
-- D. Ben Knoble