threads / discuss / 57971

Git apply fails on case-only rename on case-insensitive filesystem

Subject: Git apply fails on case-only rename on case-insensitive filesystem

## tl;dr

3 messages between Jun 8, 2022 and Jun 9, 2022.

replies: 2people: 2as markdown or json

Tao Klerks· Jun 8, 2022, 13:07 UTC · lore
Hi folks,

I just found out that "git apply" has a faulty existence check on case-insensitive filesystems (or, at least, windows?).

Simplest repro I could come up with:

git init renamefun cd renamefun echo "Test" > file1 git add . git commit -m "first commit" git mv file1 File1 git commit -m "second commit" git checkout master~1 git diff master~1..master | git apply

-> error: error: File1: already exists in working directory

(on linux, the same sequence of commands completes correctly)

I was able to work around this for my purposes by avoiding rename detection on the diff, and only passing the "Add" (and "Modify") operations through to the "apply", after having separately/manually handled the deletions.

Is this a known issue that someone might be working on, or worth digging into / trying to fix?

Thanks, Tao

brian m. carlson· Jun 8, 2022, 22:27 UTC · re: Tao Klerks · lore

Re: Git apply fails on case-only rename on case-insensitive filesystem

On 2022-06-08 at 13:07:05, Tao Klerks wrote:
Show 19 quoted lines
> Hi folks,
> 
> I just found out that "git apply" has a faulty existence check on
> case-insensitive filesystems (or, at least, windows?).
> 
> Simplest repro I could come up with:
> 
> git init renamefun
> cd renamefun
> echo "Test" > file1
> git add .
> git commit -m "first commit"
> git mv file1 File1
> git commit -m "second commit"
> git checkout master~1
> git diff master~1..master | git apply
> 
> -> error:
> error: File1: already exists in working directory

Your problem here is that the file does already exist. To Windows "file1" and "File1" are the same file. Git wants to create the new file before deleting the old one, but it already exists.

Show 9 quoted lines
> (on linux, the same sequence of commands completes correctly)
> 
> I was able to work around this for my purposes by avoiding rename
> detection on the diff, and only passing the "Add" (and "Modify")
> operations through to the "apply", after having separately/manually
> handled the deletions.
> 
> Is this a known issue that someone might be working on, or worth
> digging into / trying to fix?

As I explained to someone else just today, the rules for case-folding on Windows differ based on the version of the tool that was used to format the file system and cannot be inspected without reading the raw file system. (This is also true of macOS.) Thus, we cannot know ahead of time whether two files differ only in case.

The way we could determine this on Unix would be to stat both files and compare device and inode data when we get EEXIST, but I don't think our Windows stat emulation supports that. Having said that, for case-insensitive macOS, I think the rename detection could be fixed here using that technique. I don't think anyone's working on such a thing at the moment, though.

-- 
brian m. carlson (he/him or they/them)
Toronto, Ontario, CA
Tao Klerks· Jun 9, 2022, 04:57 UTC · re: brian m. carlson · lore

Re: Git apply fails on case-only rename on case-insensitive filesystem

On Thu, Jun 9, 2022 at 12:27 AM brian m. carlson <sandals@crustytoothpaste.net> wrote:

>
> Git wants to create the new
> file before deleting the old one, but it already exists.
>

Ah, thanks for that observation, I didn't consider that git might generally want to do renames in a "safe" order.

Show 5 quoted lines
> The way we could determine this on Unix would be to stat both files and
> compare device and inode data when we get EEXIST, but I don't think our
> Windows stat emulation supports that.  Having said that, for
> case-insensitive macOS, I think the rename detection could be fixed here
> using that technique.

I have not yet tried to find out whether this "sameness determination" is possible in windows, but I have one more interesting observation: I just realized that "git checkout" probably wants to do the same thing in the same safe order, and indeed, when I do "git config core.ignorecase false" the "checkout" command fails with a very similar error:

error: The following untracked working tree files would be overwritten
by checkout:
        file1
Please move or remove them before you switch branches.
Aborting
(in fact, even "git mv" fails with a similar error)

This suggests that there is a strategy based on the "core.ignorecase" config, which might not hinge on determining the "sameness" of differing-only-in-case files, which is applied in other places and simply wasn't considered in "git apply" yet.

> I don't think anyone's working on such a thing at
> the moment, though.
Thanks, I'll try to look a little deeper at some point.

← back to recent threads