Subject: Re: A puzzle: reset --hard and hard links

From: Junio C Hamano <[email-masked]>
Date: Wed, 26 Jan 2022 10:46:15 -0800

"brian m. carlson" <[email-masked]> writes:

> Thanks, this is helpful context and it explains why you'd want this
> behavior.  If you're involved with the project, it may be helpful to
> point out to other project members that this occurs and suggest that the
> scripts avoid running "git reset --hard".  For example, it may be easy
> to avoid if "git status --porcelain" produces empty output.  I've heard
> stories about Chromium's build times and I'm sure such an optimization
> would be welcome.

I am not sure about that.  If the ONLY problem is that hardlinks to
UNMODIFIED paths are severed by "reset --hard" when it is not necessary
in order to ensure that HEAD and the working tree matches in content
without clobbering anything unrelated, then adding an internal call
to refresh before "git reset --hard" would neatly solve it, and
there should not be a need for end-user workaround like that.

But it does not change the fact that we try to avoid clobbering
anything unrelated to the path we are updating when we need to
update the contents of the working tree files, and the way we do so
is to call checkout_entry(), which does unlink() followed by
creat().  So even though you may be able to teach "git reset --hard"
to refrain from severing extra hardlinks when it does not have to,
it will do so when the contents of the path must be changed.

To be quite honest, I am not sure if the patch below is safe either.
I doubt that the lack of "update-index --refresh" in the "reset
--hard" command was a mistake; rather, I suspect that it was
deliberately omitted to avoid some problems, which I do not offhand
recall.

 builtin/reset.c | 1 +
 1 file changed, 1 insertion(+)

diff --git c/builtin/reset.c w/builtin/reset.c
index b97745ee94..8adc1be75b 100644
--- c/builtin/reset.c
+++ w/builtin/reset.c
@@ -83,6 +83,7 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
 	}
 
 	read_cache_unmerged();
+	refresh_cache(REFRESH_QUIET);
 
 	if (reset_type == KEEP) {
 		struct object_id head_oid;