Home > Back-end >  why git merge replace the file automatically
why git merge replace the file automatically

Time:10-25

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:

  1. why git replace Foo.h with foo.h instead of reporting the conflict?
  2. 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.

  •  Tags:  
  • git
  • Related