I am writing a project with cpp. when I use git merge other_branch
I concur a wired problem:
On my branch My
, there is a header file Foo.h
in ${PROJECT_ROOT}
directory,on the branch I want to merge other_branch
, there is a header file foo.h
in ${PROJECT_ROOT}
. Foo.h
and foo.h
have different content, when I use the git merge other_branch
on My
branch, git replace Foo.h
with foo.h
. In fact, the Foo.h
disappear, only foo.h
header file exists in ${PROJECT_ROOT}
. To fix the conflict, I rename foo.h
to Foo.h
and change the content, after fixing the problem, I use git add .
and git commit -m "..."
to finish the merge. After doing this, I use git status
to see my workspace condition, I find that Foo.h
is not staged for commit. So I use git add Foo.h
to staged the file but nothing happen, Foo.h
is still not staged for commit, it's wired.
I want to know:
- why git replace
Foo.h
withfoo.h
instead of reporting the conflict? - why doesn't
git add .
work?
PS. When I see the remote repository, I find Foo.h
and foo.h
all exist. and my operating system is MacOS.
My conclusion is: git is case sensitive and MacOS's files are case insensitive, git actually want to keep foo.h
and Foo.h
but OSX regards Foo.h
and foo.h
as one file, so only foo.h
exist, when I rename foo.h
to Foo.h
git still regard Foo.h
as foo.h
, thus when I use git add Foo.h
, git add foo.h
actually, so the Foo.h
in git become a phantom.
CodePudding user response:
Even a single operating system may support filesystems with case-sensitive and case-insensitive filenames.
Although, with a lot of work, it should be possible to determine whether the underlying filesystem, where the particular git
repository lives, uses case-sensitive or case-insensitive filenames, for whatever reason this is not implementrf in the version of git
you're using and it is your responsibility to configure git
accurately. The core.ignorecase
configuration setting tells git whether the underlying filesystem is case-sensitive or case-insensitive, and should be set accordingly.
It's reasonable to expect that a pre-built git
package for a particular operating system would come pre-installed and configured with sensible defaults for the operating system. So, if an operating system uses mostly case-insensitive filenames then it would be reasonable to expect that the pre-built git
package for the operating system would be set up accordingly. But, from the looks of it, for whatever the reason, this did not happen in your case.
If git
is configured for case-sensitive filenames then git
will continue with its business accordingly, and the resulting chips will fall where they may.
why git replace Foo.h with foo.h instead of reporting the conflict?
Because git
adopted The Golden Rule Of Computer Programming: the computer always does exactly what you tell it to do instead of what you wanted it to do. This now becomes: git
always does exactly what you tell it to do instead of what you want it to do.
In this case you told git
to create or merge foo.h
. So, git proceeded and created the file foo.h
. Your operating system followed git
's instructions and clobbered the existing Foo.h
file.
why doesn't git add . work?
Because, at this point, things are hopelessly nonsensical.
The way for you to go forward would be to set core.ignoreCase
globally, and then proceed with a fresh checkout.
CodePudding user response:
Your conclusion is mostly correct: Git is case sensitive and your particular macOS file system is case-insensitive. However, macOS can work with case-sensitive file systems, and that's the way to go when merging in this repository. Here is how to create a case-sensitive macOS disk image on any existing volume, and then use that to work with Git.
CodePudding user response:
By default, Git operates in a case-sensitive way. This is the proper behaviour, since it's impossible to correctly case-fold text in a locale-insensitive way. However, you're on a file system that's case insensitive, and so Git simply cannot check out both files at once since your file system can't support that.
The reason that Git doesn't warn about this with git merge
is because different file systems fold case differently. In fact, the case-folding algorithm can depend on the version of the OS under which the file system was formatted. Unfortunately, no operating systems expose the case-folding algorithm to userspace, so Git cannot know what case-folding algorithm is in use, if any.
Git can detect this on a fresh clone because there are no existing files, so if it overwrites a file, then there must have been a conflict. However, this doesn't work when a working tree already exists.
Note that Git does automatically detect whether a file system is case insensitive and sets core.ignoreCase
for the repository if that's the case. You should not modify this setting or set it globally because that breaks Git's autodetection. However, this still doesn't let Git detect all case folding problems because it simply can't.
If you want to work with this repository, you need to either create yourself a case-sensitive APFS volume or use a Linux or other non-macOS Unix VM to do so.