threads / discuss / 15479

RFC: perhaps a "new file" should not be deleted by "git reset --hard"

Subject: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

## tl;dr

18 messages between Sep 10, 2008 and Sep 12, 2008.

replies: 17people: 7as markdown or json

Eric Raible· Sep 10, 2008, 19:12 UTC · lore

In http://marc.theaimsgroup.com/?l=git&m=114917892328066 (references by http://git.or.cz/gitwiki/GitFaq), Linus says:

'And "git reset" won't be deleting files it doesn't track (it had _better_ not touch them), even more so when it has been told to ignore them, so it makes total sense to _not_ delete them when doing that reset.'

Now consider this example:

# Create a single commit in a new repo (so that we have a HEAD) mkdir xx cd xx git init git commit --allow-empty -m"initial" # Add an important file echo "Important stuff" > file42 git add file42 git status # -> new file: file42 ls # -> file42, or course git reset --hard ls # -> nothing

I would argue that as a "new file" (as reported by git status) that file42 was never actually tracked by git. Sure, it _would_ have been tracked in the future, but git never actually tracked it (it's not part of any commits).

So in this scenario wouldn't it make more sense for "git reset --hard" to handle file42 as "git reset" does instead of deleting it w/out a trace [1]?

The same question goes for "git checkout -f", too, I suppose.

I actually accidentally deleted hundred of newly added files yesterday doing just this. https://mozy.com/?code=V3D4MM) saved my butt, but it wasn't pleasant.

- Eric

[1] - There's not even a reflog entry. Sure, "git fsck" can be used, but that's hardly a friendly fallback.

Mike Hommey· Sep 11, 2008, 06:14 UTC · re: Eric Raible · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Wed, Sep 10, 2008 at 12:12:21PM -0700, Eric Raible wrote:
Show 41 quoted lines
> In http://marc.theaimsgroup.com/?l=git&m=114917892328066
> (references by http://git.or.cz/gitwiki/GitFaq), Linus says:
> 
> 'And "git reset" won't be deleting files it doesn't track (it had _better_
> not touch them), even more so when it has been told to ignore them, so it
> makes total sense to _not_ delete them when doing that reset.'
> 
> Now consider this example:
> 
> # Create a single commit in a new repo (so that we have a HEAD)
> mkdir xx
> cd xx
> git init
> git commit --allow-empty -m"initial"
> # Add an important file
> echo "Important stuff" > file42
> git add file42
> git status # -> new file:   file42
> ls # -> file42, or course
> git reset --hard
> ls # -> nothing
> 
> I would argue that as a "new file" (as reported by git status)
> that file42 was never actually tracked by git.  Sure, it _would_
> have been tracked in the future, but git never actually tracked it
> (it's not part of any commits).
> 
> So in this scenario wouldn't it make more sense for
> "git reset --hard" to handle file42 as "git reset" does
> instead of deleting it w/out a trace [1]?
> 
> The same question goes for "git checkout -f", too, I suppose.
> 
> I actually accidentally deleted hundred of newly added files yesterday
> doing just this.  https://mozy.com/?code=V3D4MM) saved my butt,
> but it wasn't pleasant.
> 
> - Eric
> 
> [1] - There's not even a reflog entry.  Sure, "git fsck" can be
> used, but that's hardly a friendly fallback.

Note that reflog only contains references to commit sha1s, so it can't track index status. An index log could be interesting, though, but it would need to expire much faster than reflog.

Mike
Eric Raible· Sep 11, 2008, 20:26 UTC · re: Mike Hommey · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

Mike Hommey <mh <at> glandium.org> writes:
> Note that reflog only contains references to commit sha1s, so it can't
> track index status.
Yes I realize that.

My point was that the file is entirely gone (except via "git fsck"). I wouldn't expect the reflog to reference it, but I was just mentioning it for completeness (since it's often help in recovering from types of lossage).

Changsheng Jiang· Sep 11, 2008, 02:14 UTC · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

I think the current behavior is better than you described. If you want to ignore some files, you can added it to the exclude file. All files not excluded in the repo directory is maintained by git.

Elijah Newren· Sep 11, 2008, 02:38 UTC · re: Changsheng Jiang · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Wed, Sep 10, 2008 at 8:14 PM, Changsheng Jiang <jiangzuoyan@gmail.com> wrote:
> I think the current behavior is better than you described. If you want
> to ignore some files, you can added it to the exclude file. All files
> not excluded in the repo directory is maintained by git.

No, there's a limbo state -- the "untracked" files shown by git status (which is the default state; these are files that have not been explicitly requested to be ignored or be tracked). Note the quote from Linus at the beginning of Eric's email that specifically references this.

Anyway, Eric wasn't really talking about ignoring files, since he was explicitly adding them for the next commit. It's just that at some point he changed his mind and decided he didn't want to include any of the changes he had already made in the next commit, but was surprised when git reset --hard deleted the files from both the index and working copy instead of just the index. git reset --hard really is meant for throwing away unwanted stuff (particularly including in the working directory), but I can see how he may have expected behavior more along the lines of git rm --cached for those particular files. I don't agree with that viewpoint (I see files as tracked as soon as you stage it, not once you commit it), but I can see where the expectation comes from.

Just my thoughts, Elijah

Eric Raible· Sep 11, 2008, 20:50 UTC · re: Elijah Newren · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

Elijah Newren <newren <at> gmail.com> writes:
Show 15 quoted lines
> Anyway, Eric wasn't really talking about ignoring files, since he was
> explicitly adding them for the next commit.  It's just that at some
> point he changed his mind and decided he didn't want to include any of
> the changes he had already made in the next commit, but was surprised
> when git reset --hard deleted the files from both the index and
> working copy instead of just the index.  git reset --hard really is
> meant for throwing away unwanted stuff (particularly including in the
> working directory), but I can see how he may have expected behavior
> more along the lines of git rm --cached for those particular files.  I
> don't agree with that viewpoint (I see files as tracked as soon as you
> stage it, not once you commit it), but I can see where the expectation
> comes from.
> 
> Just my thoughts,
> Elijah

Yes, you have a 100% correct understand of what I'm trying to say. But can you see a downside to "git reset --hard" treating newly added files as "git reset"?

Wiping out existing files (with no realistic recovery) is a bit harsh, isn't it? Especially when AFAICS there's no downside to leaving the untracked files as they were before they were "git add"-ed.

- Eric
Junio C Hamano· Sep 11, 2008, 21:34 UTC · re: Eric Raible · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

Eric Raible <raible@gmail.com> writes:
> Yes, you have a 100% correct understand of what I'm trying to say.
> But can you see a downside to "git reset --hard" treating newly
> added files as "git reset"?

Of course. The --hard option is called --hard without inviting short option for a reason.

I am actually somewhat sympathetic to your point, but you would want "reset --hard" to remove that path when a path does not exist in the HEAD but in index in other cases. And it is my experience (and I presume you can guess I have longer git experience than any of you ;-) that far more often than not that is what is desirable.

Consider:
 (1) Your branch does not have "path";
 (2) You once thought you want addition of the "path" made in another
     branch;
 (3) So you did:
    $ git checkout another -- path
 (4) After more hacking, it turns out that the avenue you chose to reach
     your goal, including the addition of the "path", was a mistake, and
     you regret having wasted some time.  You want to go back to the
     current HEAD:
    $ git reset --hard

The state after (3) is "HEAD does not have path, index and work tree has it". In step (4) you would want "git reset --hard" to get rid of such a path.

And it is no different from the case where you add the path manually to the index. Both are "you thought you wanted it, but you changed your mind".

Another example is getting rid of crufts from a conflicted merge. It may bring in many new paths in your index and the working tree. You would want a "git reset --hard" to get rid of all of them. Not removing the paths that are not in HEAD but in index and working tree is far worse in this case because merging is often done from other people's tree that you may not be familiar with (i.e. you wanted to study their tree after merging), so it is harder for you to hand-clean after "reset" if a hard reset does not do it for you.

Eric Raible· Sep 11, 2008, 22:19 UTC · re: Junio C Hamano · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Thu, Sep 11, 2008 at 2:34 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 9 quoted lines
> Eric Raible <raible@gmail.com> writes:
>
>> But can you see a downside to "git reset --hard" treating newly
>> added files as "git reset"?
>
> Of course.  The --hard option is called --hard without inviting short
> option for a reason.
>
> [various good reasons snipped]

Thanks for the definitive response. I suppose that I had been getting rather cavalier about --hard. Now my expectations are more aligned with reality.

And that reality makes perfect sense, it's just a bit harsh when hundreds of important files get obliterated!

- Eric
Jeff Whiteside· Sep 11, 2008, 23:04 UTC · re: Eric Raible · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

The command is wrapped up in all kinds of semantics at which you have to guess or read tons of vague or outdated literature. That's what makes git's learning curve so retarded.

Why is it not just    git reset --index     or     git reset
--worktree    or   git reset --commitrepo REVISION  or   git reset
--all ?
And if you want to delete all untracked files
     ls | sed s/`git status --index --filenamesonly`//g | rm
     ls | sed s/`git status --commitrepo --filenamesonly`//g | rm
           (I realize those commands don't actually work, but I'm a noob.)

So that 'tracked by git' isn't just another ambiguous semantic. Instead 'Tracked by index'/'Tracked by commitrepo'.

Eric Raible· Sep 11, 2008, 23:29 UTC · re: Jeff Whiteside · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Thu, Sep 11, 2008 at 4:04 PM, Jeff Whiteside <jeff.m.whiteside@gmail.com> wrote:

> And if you want to delete all untracked files
>     ls | sed s/`git status --index --filenamesonly`//g | rm
>     ls | sed s/`git status --commitrepo --filenamesonly`//g | rm
>           (I realize those commands don't actually work, but I'm a noob.)
"git clean" will remove untracked files.
Eric Raible· Sep 11, 2008, 02:46 UTC · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Wed, Sep 10, 2008 at 7:12 PM, Changsheng Jiang <jiangzuoyan@gmail.com> wrote:
> I think the current behavior is better than you described. If you want to
> ignore some files, you can added it to the exclude file. All files not
> excluded in the repo directory is maintained by git.

That doesn't really address the problem. This is an updated example that specifically ignores the file:

# Create a single commit in a new repo (so that we have a HEAD) mkdir xx cd xx git init git commit --allow-empty -m"initial" # Add an important file echo "Important stuff" > file42 git add file42 echo file42 > .gitignore git status # -> new file: file42 ls # -> file42, or course git reset --hard ls # -> nothing

So not only was file42 never actually tracked by git (IMHO - I realize that this is debatable) but it was also specifically ignored, and it is _still_ deleted w/out a trace!

I realize that "git reset" will simply unstage the new file in either case (w or w/out .gitignore), but the consequences of an accidental "git reset --hard" are pretty severe in this case. This behavior seems definitely contrary to Linus's explanation:

   And "git reset" won't be deleting files it doesn't track (it had _better_
   not touch them), even more so when it has been told to ignore them, so it
   makes total sense to _not_ delete them when doing that reset.
- Eric
Changsheng Jiang· Sep 11, 2008, 06:05 UTC · re: Eric Raible · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

I don't know what version of you git, my git with version 1.5.4.5 doesn't delete the file file42 after git-reset.

BTW, if you added the file42 to .gitignore, why git-status still reported "new file" file42"?

Yours sincerely, Changsheng Jiang pubkey: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x40C37374

On Thu, Sep 11, 2008 at 10:46, Eric Raible <raible@gmail.com> wrote:
Show 38 quoted lines
> On Wed, Sep 10, 2008 at 7:12 PM, Changsheng Jiang <jiangzuoyan@gmail.com> wrote:
>> I think the current behavior is better than you described. If you want to
>> ignore some files, you can added it to the exclude file. All files not
>> excluded in the repo directory is maintained by git.
>
> That doesn't really address the problem.  This is an
> updated example that specifically ignores the file:
>
> # Create a single commit in a new repo (so that we have a HEAD)
> mkdir xx
> cd xx
> git init
> git commit --allow-empty -m"initial"
> # Add an important file
> echo "Important stuff" > file42
> git add file42
> echo file42 > .gitignore
> git status # -> new file:   file42
> ls # -> file42, or course
> git reset --hard
> ls # -> nothing
>
> So not only was file42 never actually tracked by git
> (IMHO - I realize that this is debatable) but it was also
> specifically ignored, and it is _still_ deleted w/out a trace!
>
> I realize that "git reset" will simply unstage the new file
> in either case (w or w/out .gitignore), but the consequences
> of an accidental "git reset --hard" are pretty severe in this
> case.  This behavior seems definitely contrary to Linus's
> explanation:
>
>   And "git reset" won't be deleting files it doesn't track (it had _better_
>   not touch them), even more so when it has been told to ignore them, so it
>   makes total sense to _not_ delete them when doing that reset.
>
> - Eric
>
Eric Raible· Sep 11, 2008, 06:15 UTC · re: Changsheng Jiang · lore

Re: RFC: perhaps a

Changsheng Jiang <jiangzuoyan <at> gmail.com> writes:
> 
> I don't know what version of you git, my git with version 1.5.4.5
> doesn't delete the file file42 after git-reset.
All examples from me are version 1.6.0.1.436.g09e16c.dirty or later.
Elijah Newren· Sep 11, 2008, 16:32 UTC · re: Changsheng Jiang · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Thu, Sep 11, 2008 at 12:05 AM, Changsheng Jiang <jiangzuoyan@gmail.com> wrote:

> I don't know what version of you git, my git with version 1.5.4.5
> doesn't delete the file file42 after git-reset.

He stated the same with his version. The point wasn't the behavior of git reset, but of git reset --hard.

> BTW, if you added the file42 to .gitignore, why git-status still
> reported "new file" file42"?
>From the gitignore(5) manpage:

"Note that all the gitignore files really concern only files that are not already tracked by git; in order to ignore uncommitted changes in already tracked files, please refer to..."

Once you run git add, the file is tracked (unless you do something to explicitly stop tracking it).

Hope that helps, Elijah

Eric Raible· Sep 11, 2008, 21:24 UTC · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Thu, Sep 11, 2008 at 10:22 AM, Jeff Whiteside <jeff.m.whiteside@gmail.com> wrote:

> And if you want to delete all untracked files
>      ls | sed s/`git status --index --filenamesonly`//g | rm
>      ls | sed s/`git status --commitrepo --filenamesonly`//g | rm
>            (I realize those commands don't actually work, but I'm a noob.)

"git clean" (http://www.kernel.org/pub/software/scm/git/docs/git-clean.html) will delete untracked file.

> So that 'tracked by git' isn't just another ambiguous semantic.

While I can't find where it might be explicitly defined, it does seem clear that a file/dir is "tracked" as soon as it's added.

My question is why "git reset --hard" can't make a special case for _newly added_ tracked files. After all, "git status" knows that they're "new files", and "git reset --hard" could realize that wiping them off the face of the earth isn't the most helpful thing possible.

- Eric
Miklos Vajna· Sep 11, 2008, 23:39 UTC · re: Eric Raible · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Thu, Sep 11, 2008 at 02:24:51PM -0700, Eric Raible <raible@gmail.com> wrote:
> My question is why "git reset --hard" can't make a special case for
> _newly added_ tracked files.  After all, "git status" knows that they're
> "new files", and "git reset --hard" could realize that wiping them off
> the face of the earth isn't the most helpful thing possible.

I rarely need this, but I use 'git read-tree -m HEAD' before git reset --hard in case I want such a behaviour.

Eric Raible· Sep 11, 2008, 23:49 UTC · re: Miklos Vajna · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Thu, Sep 11, 2008 at 4:39 PM, Miklos Vajna <vmiklos@frugalware.org> wrote:
Show 8 quoted lines
> On Thu, Sep 11, 2008 at 02:24:51PM -0700, Eric Raible <raible@gmail.com> wrote:
>> My question is why "git reset --hard" can't make a special case for
>> _newly added_ tracked files.  After all, "git status" knows that they're
>> "new files", and "git reset --hard" could realize that wiping them off
>> the face of the earth isn't the most helpful thing possible.
>
> I rarely need this, but I use 'git read-tree -m HEAD' before git reset
> --hard in case I want such a behaviour.

What advantages does "git read-tree -m HEAD" have over "git reset" or "git rm --cached <file list>"?

Miklos Vajna· Sep 12, 2008, 15:41 UTC · re: Eric Raible · lore

Re: RFC: perhaps a "new file" should not be deleted by "git reset --hard"

On Thu, Sep 11, 2008 at 04:49:54PM -0700, Eric Raible <raible@gmail.com> wrote:
> What advantages does "git read-tree -m HEAD" have over "git reset" or
> "git rm --cached <file list>"?

Nothing. I should stop advertising that I still use a lot of plumbing when a porcelain like 'git reset' does the job as well. ;-(

Thanks for the correction.

← back to recent threads