threads / rfc / 64608

[RFC] reset --hard: warn before discarding staged content with no commit history

Subject: [RFC] reset --hard: warn before discarding staged content with no commit history

## tl;dr

13 messages between Dec 10, 2025 and Dec 15, 2025.

replies: 12people: 6as markdown or json

Koutsouflakis Stefanos· Dec 10, 2025, 15:01 UTC · lore

When running "git reset --hard" in a repository where staged content has never been committed, the staged files are lost. This seems like a case where requiring --force could be helpful.

Reproduction:
    mkdir test && cd test
    git init
    echo "hello" > a.txt
    git add .
    git reset --hard
Result: a.txt is removed from both the index and working tree.
While the blob temporarily remains as a dangling object (recoverable
via "git fsck --lost-found" until garbage collection), this is not a
realistic safety net as the filename is lost and most users are
unaware of this recovery mechanism.

The most likely scenario is a user initializing a Git repository in an existing project. They have a folder with files they've been working on, run "git init", then "git add ." to stage everything. A mistyped or misunderstood command later, their entire project is wiped out.

Proposed behavior:

When "git reset --hard" would discard staged content that does not exist in any commit (i.e., the blob has no reachable reference), print a warning and require confirmation or --force:

    warning: the following staged files have never been committed
    and will be permanently lost:
        a.txt
    use --force to proceed, or commit first

This would be consistent with Git's general trend toward safer defaults.

Questions for discussion:
1. Is this safety check worth the added complexity?
2. Are there workflows where this would be annoying? (can't think of any but I might be missing something).
I'm happy to work on a patch if there's interest.

Thanks, Stefanos

Junio C Hamano· Dec 11, 2025, 03:24 UTC · re: Koutsouflakis Stefanos · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

Koutsouflakis Stefanos <koutsouflakis.stefanos@proton.me> writes:
> When running "git reset --hard" in a repository where staged
> content has never been committed, the staged files are lost. This
> seems like a case where requiring --force could be helpful.

The thinking has always been "'--hard' means what it says! HARD removes things harder than other modes---there is need to add '--force' to it".

So, I dunno.
Eric Sunshine· Dec 11, 2025, 03:59 UTC · re: Junio C Hamano · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

On Wed, Dec 10, 2025 at 10:24 PM Junio C Hamano <gitster@pobox.com> wrote:
Show 8 quoted lines
> Koutsouflakis Stefanos <koutsouflakis.stefanos@proton.me> writes:
> > When running "git reset --hard" in a repository where staged
> > content has never been committed, the staged files are lost. This
> > seems like a case where requiring --force could be helpful.
>
> The thinking has always been "'--hard' means what it says!  HARD
> removes things harder than other modes---there is need to add
> '--force' to it".
Presumably, you meant "there is *no* need" rather than "there is need".
Junio C Hamano· Dec 11, 2025, 05:25 UTC · re: Eric Sunshine · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

Eric Sunshine <sunshine@sunshineco.com> writes:
Show 11 quoted lines
> On Wed, Dec 10, 2025 at 10:24 PM Junio C Hamano <gitster@pobox.com> wrote:
>> Koutsouflakis Stefanos <koutsouflakis.stefanos@proton.me> writes:
>> > When running "git reset --hard" in a repository where staged
>> > content has never been committed, the staged files are lost. This
>> > seems like a case where requiring --force could be helpful.
>>
>> The thinking has always been "'--hard' means what it says!  HARD
>> removes things harder than other modes---there is need to add
>> '--force' to it".
>
> Presumably, you meant "there is *no* need" rather than "there is need".

Thanks. I rewrote the paragraph a few times and somehow losing the crucial negation from there..

Koutsouflakis Stefanos· Dec 11, 2025, 11:53 UTC · re: Junio C Hamano · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

On Wed, Dec 10, 2025 at 10:24 PM Junio C Hamano <gitster@pobox.com> wrote:
Show 8 quoted lines
> Koutsouflakis Stefanos <koutsouflakis.stefanos@proton.me> writes:
> > When running "git reset --hard" in a repository where staged
> > content has never been committed, the staged files are lost. This
> > seems like a case where requiring --force could be helpful.
>
> The thinking has always been "'--hard' means what it says!  HARD
> removes things harder than other modes---there is need to add
> '--force' to it".
I agree that "--hard" conveys serious intent. But I would argue there is a meaningful difference between "lose your uncommitted changes" and "lose your entire project".

To be clear, I'm addressing a very narrow scenario: the user has run init on an existing codebase, staged files with git add, but has not yet made a first commit. Running reset --hard at this point destroys the entire project with no realistic recovery path. This is almost certainly never intentional.

Thanks, Stefanos

Johannes Sixt· Dec 11, 2025, 12:22 UTC · re: Koutsouflakis Stefanos · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

Am 11.12.25 um 12:53 schrieb Koutsouflakis Stefanos:
Show 15 quoted lines
> On Wed, Dec 10, 2025 at 10:24 PM Junio C Hamano <gitster@pobox.com> wrote:
>> The thinking has always been "'--hard' means what it says!  HARD
>> removes things harder than other modes---there is [no] need to add
>> '--force' to it".
> 
> I agree that "--hard" conveys serious intent. But I would argue
> there is a meaningful difference between "lose your uncommitted
> changes" and "lose your entire project".
> 
> To be clear, I'm addressing a very narrow scenario:
> the user has run init on an existing codebase, staged files
> with git add, but has not yet made a first commit. Running
> reset --hard at this point destroys the entire project
> with no realistic recovery path. This is almost certainly
> never intentional.

I would argue that bad "tutorials" and "recipes" are to blame. I have seen far too many that casually suggest `git reset --hard` without warning and in an easy to copy-and-paste format.

Wouldn't the following slightly different scenario warrant a similar safety net:

   git commit --allow-empty -m "Initial commit"
   git add .
   git reset --hard

That said, I have some sympathy for the case. Would it be palatable to have `git reset --hard` refuse to do anything if the destination tree is empty?

-- Hannes
Koutsouflakis Stefanos· Dec 11, 2025, 16:33 UTC · re: Johannes Sixt · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

On Thursday, December 11th, 2025 at 14:34, Johannes Sixt <j6t@kdbg.org> wrote:
Show 22 quoted lines
> Am 11.12.25 um 12:53 schrieb Koutsouflakis Stefanos:
> 
> > On Wed, Dec 10, 2025 at 10:24 PM Junio C Hamano gitster@pobox.com wrote:
> > 
> > > The thinking has always been "'--hard' means what it says! HARD
> > > removes things harder than other modes---there is [no] need to add
> > > '--force' to it".
> > 
> > I agree that "--hard" conveys serious intent. But I would argue
> > there is a meaningful difference between "lose your uncommitted
> > changes" and "lose your entire project".
> > 
> > To be clear, I'm addressing a very narrow scenario:
> > the user has run init on an existing codebase, staged files
> > with git add, but has not yet made a first commit. Running
> > reset --hard at this point destroys the entire project
> > with no realistic recovery path. This is almost certainly
> > never intentional.
> 
> I would argue that bad "tutorials" and "recipes" are to blame. I have
> seen far too many that casually suggest `git reset --hard` without
> warning and in an easy to copy-and-paste format.
Agreed. Many users copy-paste their way through Git or use commands
they don't fully understand. That's not the ideal way to interact with 
Git, but they don't deserve do be punished.
 
Show 5 quoted lines
> That said, I have some sympathy for the case. Would it be palatable to
> have `git reset --hard` refuse to do anything if the destination tree is
> empty?
> 
> -- Hannes

Good point. Checking for an empty destination tree seems to be the better approach. Refusing to proceed (without providing the option of bypassing it with --force) also seems reasonable, maybe with a helpful message explaining the reason. On a second thought "--hard --force" is a bit redundant, like "rm -rf --really-delete".

Thanks, Stefanos

Junio C Hamano· Dec 12, 2025, 03:24 UTC · re: Johannes Sixt · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

Johannes Sixt <j6t@kdbg.org> writes:
Show 6 quoted lines
> Wouldn't the following slightly different scenario warrant a similar
> safety net:
>
>    git commit --allow-empty -m "Initial commit"
>    git add .
>    git reset --hard

Yes, I think everybody has lost new files not in an empty tree but more often (1) create a new file and add it, (2) make modifications to existing files, (3) compile, test, debug, get frustrated, and finally (4) decide to give up and start from scratch, with "reset --hard". When (1) is much larger than (2), the sense of loss is big.

> That said, I have some sympathy for the case. Would it be palatable to
> have `git reset --hard` refuse to do anything if the destination tree is
> empty?
I doubt that special casing an empty tree would fly well.

It is tempting to special case removals, but then I sill am not sure it is good to do nothing and fail the command after determining that the operation is a common pitfall of removing a new file that appears nowhere else. Unconditionally going interactive is a no-no.

And I do not have any better ideas. Other than just failing, that is. But that leads to nonsense combination "--hard --force", just as idiotic combination as "rm -f -i" :-/

Koutsouflakis Stefanos· Dec 14, 2025, 13:29 UTC · re: Junio C Hamano · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

On Friday, December 12th, 2025 at 05:25, Junio C Hamano <gitster@pobox.com> wrote:
> I doubt that special casing an empty tree would fly well.

I might be missing something, could you say more about what makes this problematic? If it is about breaking existing workflows: any script that automates either of the two use-cases discussed would be relying on behavior that is almost certainly unintended. Such scripts would fail, but without data loss, and give authors a clear signal to fix a likely bug.

> And I do not have any better ideas.  Other than just failing, that is.
> But that leads to nonsense combination "--hard --force", just as
> idiotic combination as "rm -f -i" :-/
There might be other ways to mitigate this, e.g.:
a) Refuse with a fatal error and hint the user
   to remove staged content with "git rm --cached -r ."
b) Autostash with a warning 

Thanks, Stefanos

Štefan Balog· Dec 14, 2025, 13:45 UTC · re: Koutsouflakis Stefanos · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

Dôvera, spolupráca, jednota ! Jedina cesta posunu genetického kódu a vyvoja pre zlepšenie kvality života ľudí a spoločnosti v ktorej víťazí dokonalá súhra dôvery viery a nádeje v lepší svet v symbióze s kozmom.

World Rescue Organization

Dňa ne, 14. dec 2025, 14:30 Koutsouflakis Stefanos < koutsouflakis.stefanos@proton.me> napísal(a):

Show 26 quoted lines
> On Friday, December 12th, 2025 at 05:25, Junio C Hamano <gitster@pobox.com>
> wrote:
>
> > I doubt that special casing an empty tree would fly well.
>
> I might be missing something, could you say more about
> what makes this problematic?
> If it is about breaking existing workflows: any script that
> automates either of the two use-cases discussed would be relying
> on behavior that is almost certainly unintended. Such scripts
> would fail, but without data loss, and give authors a clear
> signal to fix a likely bug.
>
> > And I do not have any better ideas.  Other than just failing, that is.
> > But that leads to nonsense combination "--hard --force", just as
> > idiotic combination as "rm -f -i" :-/
>
> There might be other ways to mitigate this, e.g.:
> a) Refuse with a fatal error and hint the user
>    to remove staged content with "git rm --cached -r ."
> b) Autostash with a warning
>
> Thanks,
> Stefanos
>
>
Junio C Hamano· Dec 14, 2025, 23:27 UTC · re: Koutsouflakis Stefanos · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

Koutsouflakis Stefanos <koutsouflakis.stefanos@proton.me> writes:
Show 6 quoted lines
> On Friday, December 12th, 2025 at 05:25, Junio C Hamano <gitster@pobox.com> wrote:
>
>> I doubt that special casing an empty tree would fly well.
>
> I might be missing something, could you say more about 
> what makes this problematic? 
Inconsistency.

Treating "newly added files" specifically is making the behaviour inconsistent with others already, but doing so only when you haven't created a commit or after doing "checkout/switch --orphan", which is essentially what special-casing an empty tree case is about, makes it even more inconsistent.

> If it is about breaking existing workflows: any script that 
> automates either of the two use-cases discussed would be relying 
> on behavior that is almost certainly unintended.

I do not think that is the reason for "special casing an empty tree would not fly well", but I have to say your view is too narow. I do rely on "reset --hard && clean -f -x" working in order to make the working tree spiffy clean, and I somehow doubt I am in the minority. And "reset --hard" MUST not fail in such a case.

> Such scripts 
> would fail, but without data loss, and give authors a clear 
> signal to fix a likely bug. 

And most authors will consider the "bug" to be fixed is in the degraded behaviour of "reset --hard". that does not do what is written on the label Then what?

Koutsouflakis Stefanos· Dec 15, 2025, 07:22 UTC · re: Junio C Hamano · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

On Monday, December 15th, 2025 at 01:27, Junio C Hamano <gitster@pobox.com> wrote:
Show 27 quoted lines
> Inconsistency.
> 
> Treating "newly added files" specifically is making the behaviour
> inconsistent with others already, but doing so only when you haven't
> created a commit or after doing "checkout/switch --orphan", which is
> essentially what special-casing an empty tree case is about, makes
> it even more inconsistent.
> 
> > If it is about breaking existing workflows: any script that
> > automates either of the two use-cases discussed would be relying
> > on behavior that is almost certainly unintended.
> 
> 
> I do not think that is the reason for "special casing an empty tree
> would not fly well", but I have to say your view is too narow. I do
> rely on "reset --hard && clean -f -x" working in order to make the
> working tree spiffy clean, and I somehow doubt I am in the minority.
> And "reset --hard" MUST not fail in such a case.
> 
> > Such scripts
> > would fail, but without data loss, and give authors a clear
> > signal to fix a likely bug.
> 
> 
> And most authors will consider the "bug" to be fixed is in the
> degraded behaviour of "reset --hard". that does not do what is
> written on the label Then what?

That actually makes sense. For tools as versatile as Git, it is sometimes hard to see the bigger picture and the different ways of people using it. I'll drop the proposal, and thanks everyone for your time.

-- Stefanos
D. Ben Knoble· Dec 12, 2025, 22:14 UTC · re: Koutsouflakis Stefanos · lore

Re: [RFC] reset --hard: warn before discarding staged content with no commit history

On Wed, Dec 10, 2025 at 10:04 AM Koutsouflakis Stefanos <koutsouflakis.stefanos@proton.me> wrote:

Show 48 quoted lines
>
> When running "git reset --hard" in a repository where staged content
> has never been committed, the staged files are lost. This seems like a case where requiring --force could be helpful.
>
> Reproduction:
>
>     mkdir test && cd test
>     git init
>     echo "hello" > a.txt
>     git add .
>     git reset --hard
>
> Result: a.txt is removed from both the index and working tree.
> While the blob temporarily remains as a dangling object (recoverable
> via "git fsck --lost-found" until garbage collection), this is not a
> realistic safety net as the filename is lost and most users are
> unaware of this recovery mechanism.
>
> The most likely scenario is a user initializing a Git repository in an
> existing project. They have a folder with files they've been working on,
> run "git init", then "git add ." to stage everything. A mistyped or
> misunderstood command later, their entire project is wiped out.
>
> Proposed behavior:
>
> When "git reset --hard" would discard staged content that does not
> exist in any commit (i.e., the blob has no reachable reference),
> print a warning and require confirmation or --force:
>
>     warning: the following staged files have never been committed
>     and will be permanently lost:
>         a.txt
>     use --force to proceed, or commit first
>
> This would be consistent with Git's general trend toward safer
> defaults.
>
> Questions for discussion:
>
> 1. Is this safety check worth the added complexity?
>
> 2. Are there workflows where this would be annoying? (can't think of any but I might be missing something).
>
> I'm happy to work on a patch if there's interest.
>
> Thanks,
> Stefanos
>

Perhaps useful for future readers who are looking for ways to recover the objects: https://blog.plover.com/prog/git-reset-disaster.html

-- 
D. Ben Knoble

← back to recent threads