git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [RFC] builtin/stash: data loss from reset --hard

From
Junio C Hamano <gitster@pobox.com>
Date
Jan 5, 2026, 01:47 UTC
Message-ID
<xmqqms2sn83d.fsf@gitster.g>
In-Reply-To
<-98ze4v1cX5P2d_tlWY6nBZuQhY3J7OJLJX51VS53bVhirt-Gm9zA6E_Y-pNMMYhtcLN2MM_miuPfR_Nrq5JCUWDgI_BwG9rUxtuBoqf8h0=@protonmail.com>
Tsahi Elkayam <Tsahi.Elkayam@protonmail.com> writes:
Show 20 quoted lines
> Hi,
>
> I am a beginner C developer exploring the Git codebase and came across
> something I would like to understand better.
>
> In builtin/stash.c line 1747, there is a comment:
>
>     /* BUG: this nukes untracked files in the way */
>     strvec_pushl(&cp.args, "reset", "--hard", "-q",
>                  "--no-recurse-submodules", NULL);
>
> Steps to reproduce:
>
>     $ git init test && cd test
>     $ echo "tracked" > foo && git add foo && git commit -m "init"
>     $ git rm foo
>     $ mkdir foo && echo "precious" > foo/file
>     $ git stash
>     $ cat foo/file
>     cat: foo/file: Not a directory   # precious data is lost

As far as I can see, everything I see in the above is working as intended. "stash" is a way to get rid of your work in progress and take you back to the pristine state quickly (after all, it is "panic! the boss is here and tells me to work on something else, clear the desk real quick now" option), so after "git stash", whatever change you made relative to the pristine state (that is, a regular file 'foo' exists and has "tracked" in it) should go away, if it gets in a way in order to get us back to the pristine state.

After the above sequence, if you "git stash pop", it should get you back to the state immediately before you did "git stash [push]", but depending on what you did between push and pop, it is possible that the changes conflict and "stash pop" may fail without popping the stash entry. This is to allow you to attempt to pop it again later after cleaning up the mess (like, perhaps going back to the state before you did "stash push" on a new branch). The point to note here is that the "push" operation cannot afford to fail at the "panic! the boss is here" moment, but at the "stash pop" stage, aka "the crisis is over, now let's get back to where we were", the user can afford to see a failure and spend time on conflict resolution.

Another thing to note is that the new foo/file in the above example is not tracked, and IIUC, "git stash" by default will not save random untracked cruft found in the working tree. I wasn't heavily involved in the design of this optional feature of saving away the untracked cruft ("git stash push -u"), so I do not offhand know if the contents of foo/file is saved away correctly in the above sequence of yours if you changed your "git stash" to "git stash [push] -u", or if it is recovered when you later say "git stash pop" (and if it doesn't, then you have found a bug there). But it does not change the fact that the "cat" in the above sequence immediately after "git stash [push]" with or without "-u" should notice that foo/file is now gone, once you got back to the pristine state.

I do not know what "BUG:" comment refers to in the above. Without "-u", getting rid of untracked files that get in the way of going back to the pristine state is absolutely the right thing to do, so there is no bug there. It is possible that it is done way too early even when "-u" is given, making it impossible to save away such an untracked files that are in the way, but I didn't check.

Previous: Tsahi Elkayam
Message 2 of 2 in “[RFC] builtin/stash: data loss from reset --hard”
  1. Tsahi ElkayamJan 4, 2026
  2. Junio C HamanoJan 5, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.