From: "Torsten Bögershausen" <tboegi@web.de>
To: Curtis Allen Smith <curtis.allen.smith@gmail.com>
Cc: git@vger.kernel.org, Junio C Hamano <gitster@pobox.com>
Subject: Re: [PATCH v4] read-cache: do not trust a size change when conversion is active
Date: Tue, 13 Oct 2026 20:01:16 +0200 [thread overview]
Message-ID: <20261013180116.GA26647@tb-raspi4> (raw)
In-Reply-To: <20261013065915.879-1-curtis.allen.smith@gmail.com>
On Tue, Oct 13, 2026 at 12:58:28AM -0600, Curtis Allen Smith wrote:
Thanks for the fast and good answers everybody.
As a comment: no, I didn't intend to tak over the series -
just want to move things forward.
And the Helped-By is of course ok.
I don't know if we need more explanations why this change
is needed (after so long time), but here is my undestanding:
When we run
git init t && cd t
printf 'one\ntwo\nthree\n' >file.txt
git add . && git commit -m init
followed by
printf 'two\ntwo\nthree\n' >file.txt
then Git will notice that the actual mtime as a result of lstat()
is different from what is recorded in the index.
As a result, git needs to re-hash the content to conclude if the
content has changed.
However, in order to avoid the expensive hashing,
Git concludes that when the size of a file has changed
then the content -must- be different - files having a different size
are never identical.
This did work well until the .gitattributes feature was introduced.
Now, in the example below, a file having a different size -can-
result in the same blob once it is commited.
Therefore this patch does need to check if attributes
(for input conversions) are defined.
If not, take the shortcut and conclude that the file is modified.
But if, take the long way, which is what happens when only mtime
(and possibly other elements from struct st are changed.
And now the new size, mtime (and the rest)
will be recorded in the index. So it is a one-time cost.
Does this make sense ?
> "git status" can report a file as modified while "git diff" and
> "git add" agree that its contents are unchanged:
>
> git init t && cd t
> printf '* text eol=lf\n' >.gitattributes
> printf 'one\ntwo\nthree\n' >file.txt
> git add . && git commit -m init
>
> printf 'one\r\ntwo\r\nthree\r\n' >file.txt
>
> git status --short # -> M file.txt
> git diff # -> empty
> git add file.txt # -> nothing to commit
>
> ie_modified() takes a change in the file's size since the index
> entry was last refreshed as proof that the file is modified, without
> looking at the contents. A size change proves only that the bytes in
> the working tree changed. When the path is subject to conversion
> (the "text" and "eol" attributes, core.autocrlf, a clean filter),
> different bytes can convert to the same blob, as the CRLF rewrite
> above does.
>
> For such a path, fall through to ce_modified_check_fs(), as is
> already done when only the mtime changed. Paths without conversion
> return early as before.
>
> Helped-by: Torsten Bögershausen <tboegi@web.de>
> Signed-off-by: Curtis Allen Smith <curtis.allen.smith@gmail.com>
> ---
> Changes since v3:
> - The fix is inlined into the condition in ie_modified(), with no
> helper function.
> - Shorter log message, using Junio's wording; the "real life"
> examples are gone.
>
> Cost, i9-14900K under WSL2, warm cache, fastest of 5 runs of
> "git status -uno", stock 6de20f6 against this patch:
>
> 10000 files x 2.6 KB, no conversion stock v4
> clean tree 5 ms 5 ms
> 10000 files with a size change 26 ms 24 ms
>
> 10000 files x 2.6 KB, "* text=auto eol=lf"
> clean tree 5 ms 5 ms
> 10000 genuinely modified 25 ms 137 ms
> 10000 CRLF-rewritten, 1st run 21 ms 143 ms
> the same, every run after 21 ms 5 ms
>
> 200 files x 1 MB, "* text=auto eol=lf"
> clean tree 3 ms 3 ms
> 200 genuinely modified 3 ms 498 ms
> 200 CRLF-rewritten, 1st run 3 ms 584 ms
> the same, every run after 3 ms 3 ms
>
> The attribute lookup happens only for a path whose size changed, so a
> clean tree pays nothing, and a tree without conversion pays one
> lookup per size-changed path (the first block). A converted path
> whose size changed is now read, converted and hashed, which is what
> already happens when only its mtime changes. Stock git keeps
> reporting the CRLF-rewritten files as modified on every run.
>
> A follow-up that skips the conversion and the hash when the length
> already rules out a match is ready if wanted. It takes the
> "genuinely modified" rows to 57 ms and 25 ms.
[snip]
next prev parent reply other threads:[~2026-10-13 18:01 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-11 19:51 [PATCH v2 1/2] utf8.c: Prepare workaround for iconv under macOS 14/15 tboegi
2026-01-12 4:58 ` Junio C Hamano
2026-01-12 16:25 ` [PATCH v3 0/2] Workaround " tboegi
2026-01-12 16:25 ` [PATCH v3 1/2] utf8.c: Prepare workaround " tboegi
2026-01-12 16:25 ` [PATCH v3 2/2] utf8.c: Enable " tboegi
2026-10-12 17:56 ` [PATCH v3/RFC 0/1] read-cache: do not trust a size change when conversion tboegi
2026-10-12 17:56 ` [PATCH v3/RFC 1/1] read-cache: do not trust a size change when conversion is active tboegi
2026-10-12 19:11 ` Junio C Hamano
2026-10-13 1:29 ` Junio C Hamano
2026-10-13 6:45 ` Curtis Smith
2026-10-13 5:34 ` Johannes Sixt
2026-10-13 6:48 ` Curtis Smith
2026-10-13 6:58 ` [PATCH v4] " Curtis Allen Smith
2026-10-13 9:44 ` Phillip Wood
2026-10-13 17:57 ` Curtis Smith
2026-10-13 18:01 ` Torsten Bögershausen [this message]
2026-10-13 18:02 ` [PATCH v5] " Curtis Allen Smith
2026-10-13 20:29 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261013180116.GA26647@tb-raspi4 \
--to=tboegi@web.de \
--cc=curtis.allen.smith@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox