On Sun, Sep 5, 2021 at 3:31 PM Junio C Hamano <gitster@xxxxxxxxx> wrote: > > Elijah Newren <newren@xxxxxxxxx> writes: > > > unpack_trees. In fact, it traces back to (and before) > > fcc387db9b ("read-tree -m -u: do not overwrite or remove untracked > > working tree files.", 2006-05-17) > > which has additional commentary over at > > https://lore.kernel.org/git/7v8xp1jc9h.fsf_-_@xxxxxxxxxxxxxxxxxxxxxxxx/. > > It appears that before this time, git happily nuked untracked files > > and considered them expendable, in basically all cases. However, this > > patch continued considering them as expendable whenever opts->reset > > was true. > > Thanks for digging. Yes, the 'reset' bit was treated as the license > to kill untracked working tree files and directories that get in the > way in order to carry out the unpack_trees operation. > > > So, then...should we preserve untracked (and non-ignored) files in all > > these cases? This rebase case seems clear, but others might be less > > clear.... > > In short, the guiding principle ought to be that "checkout --force" > and anything that is given "force" as a stronger override should be > allowed to do whatever minimally necessary to match the end result > in the working tree to what the command wants to show in the absense > of these untracked paths. And without being forced, untracked and > unignored paths are precious and should cause commands to fail, if > they need to be touched for the commands to complete what they are > asked to do [*]. > > "reset --hard HEAD" is an oddball. > > Naïvely, because it is often used as the way to tell Git to "no > matter what, match the working tree to HEAD", even though it does > not have an explicit "--force" on the command line, it feels that it > also should be allowed to do whatever necessary to the working tree > files. And historically, that is what we wanted to implement. If > we suddenly made it "safer", I am sure a lot of existing things will > break. > > But unfortunately, "--hard" means a bit more than that in the > context of "reset", in that we want to reset in a way that is > different from "--mixed" (reset the index only without touching the > working tree) and "--soft" (do not touch the index or the working > tree), more specifically, with "--hard", we want to reset both the > index and the working tree to match the given committish (often > "HEAD"). From that point of view, "reset --hard" that tries to > preserve untracked and unignored paths, and "reset --force --hard" > that does whatever necessary to untracked and unignored paths to > match the working tree files, when they reset the index and the > working tree to the named committish, may have made sense. If we > were designing the feature without any existing users, it is no > brainer to imagine that our design would: (1) call the three 'reset' > modes as "both", "index-only" and "neither", instead of "hard", > "mixed" and "soft", and (2) require "--force" to touch untracked and > unignored paths. > > And I think that may be a reasonable longer-term goal, but since we > have existing users and scripts, we cannot go there overnight without > devising a migration path. Sounds reasonable. I'm presuming that `read-tree --reset` is also an oddball, but as plumbing it's better to keep its behavior as-is, i.e. let it nuke untracked files/directories too. Let me know if you would prefer otherwise. I have a bunch of relatively small patches (https://github.com/git/git/pull/1085, if you want a preview), which fix most of the problems I found. I'm going to split it up into five patch series, the first three of which are independent and shorter than the remaining two.