git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
@ 2025-09-16 20:29 Anselm Schüler
  2025-09-16 20:34 ` Anselm Schüler
  2025-09-16 20:52 ` D. Ben Knoble
  0 siblings, 2 replies; 7+ messages in thread
From: Anselm Schüler @ 2025-09-16 20:29 UTC (permalink / raw)
  To: git

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?


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
  2025-09-16 20:29 Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not? Anselm Schüler
@ 2025-09-16 20:34 ` Anselm Schüler
  2025-09-16 20:48   ` Junio C Hamano
  2025-09-16 20:52 ` D. Ben Knoble
  1 sibling, 1 reply; 7+ messages in thread
From: Anselm Schüler @ 2025-09-16 20:34 UTC (permalink / raw)
  To: git

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?



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
  2025-09-16 20:34 ` Anselm Schüler
@ 2025-09-16 20:48   ` Junio C Hamano
  0 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2025-09-16 20:48 UTC (permalink / raw)
  To: Anselm Schüler; +Cc: git

Anselm Schüler <mail@anselmschueler.com> writes:

> $ 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?

> 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?

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
  2025-09-16 20:29 Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not? Anselm Schüler
  2025-09-16 20:34 ` Anselm Schüler
@ 2025-09-16 20:52 ` D. Ben Knoble
  2025-09-17 12:12   ` Junio C Hamano
  1 sibling, 1 reply; 7+ messages in thread
From: D. Ben Knoble @ 2025-09-16 20:52 UTC (permalink / raw)
  To: Anselm Schüler; +Cc: git, Junio C Hamano

On Tue, Sep 16, 2025 at 4:36 PM Anselm Schüler <mail@anselmschueler.com> wrote:
>
> 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 a

gives

    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 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

(But the point about having nowhere to restore from stands!)

-- 
D. Ben Knoble

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
  2025-09-16 21:51 ` Fwd: " Anselm Schüler
@ 2025-09-17  8:03   ` Chris Torek
  0 siblings, 0 replies; 7+ messages in thread
From: Chris Torek @ 2025-09-17  8:03 UTC (permalink / raw)
  To: Anselm Schüler; +Cc: git

[resend as plain text]

On Tue, Sep 16, 2025 at 2:53 PM Anselm Schüler <mail@anselmschueler.com> wrote:
> ... I would’ve assumed git-rm simply removes the file
> and “writes” that removal to the staged changes.

More precisely, it removes the file from the working tree
and removes the index entry that would cause the index
copy of the file to be in the next commit.

> This seems to be what y’all are
> describing. But with that suggestion, I was confused, because I assumed
> git-rm there would be equivalent in some sense to git-restore in a
> repository with commits.
>
> Could git-restore be made to work anyway, by “imagining” a
> pre-initial-commit commit that has absolutely nothing in it?

Yes, and in fact a number of Git internal operations work this
way, by pretending the commit before the first commit has as
its tree the empty tree. If `git restore` did that here it would
Just Work. (This is part of why the empty tree always seems
to exist.)

Whether this is a Good Idea, I leave to others to judge, as
I'm too well steeped in Git internals to tell any more. :-)

Chris

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
  2025-09-16 20:52 ` D. Ben Knoble
@ 2025-09-17 12:12   ` Junio C Hamano
  2025-09-17 15:33     ` D. Ben Knoble
  0 siblings, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2025-09-17 12:12 UTC (permalink / raw)
  To: D. Ben Knoble; +Cc: Anselm Schüler, git

"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.

> (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".


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not?
  2025-09-17 12:12   ` Junio C Hamano
@ 2025-09-17 15:33     ` D. Ben Knoble
  0 siblings, 0 replies; 7+ messages in thread
From: D. Ben Knoble @ 2025-09-17 15:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Anselm Schüler, git

On Wed, Sep 17, 2025 at 8:12 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> "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

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-09-17 15:33 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-16 20:29 Why does git-status suggest different commands to unstage files depending on whether there is a commit yet or not? Anselm Schüler
2025-09-16 20:34 ` Anselm Schüler
2025-09-16 20:48   ` Junio C Hamano
2025-09-16 20:52 ` D. Ben Knoble
2025-09-17 12:12   ` Junio C Hamano
2025-09-17 15:33     ` D. Ben Knoble
     [not found] <8e1905c7-7744-444f-9a39-ca809edb6896@anselmschueler.com>
2025-09-16 21:51 ` Fwd: " Anselm Schüler
2025-09-17  8:03   ` Chris Torek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).