How to prevent git from writing two files with names that differ only in case?

We are developing in a mixed environment - some work on Mac and work on Linux. This turned out to be a problem from time to time, as those people who work on Linux are used to the fact that their file systems are case sensitive, so there are no problems associated with (accidentally or otherwise) several files that differ in each case. (e.g. FileName.ext compared to FileName.ext )

However, when people on a Mac set off to check the repository, having a case-insensitive file system means that two files - only different in the case - overwrite each other and cause general chaos.

I know that there are various git settings that help people in case-insensitive file systems work better with case changes (e.g. core.ignorecase ), but this does not solve the problem when there are two different files in the repository, only depending on the case .

I understand that the only way to fix this is to make sure that Linux people do not commit two files that differ only if they are in the first place. - Is there any setting in git that gives a warning or an error if a user tries to commit files (files) that will be confused with each other in a file system without a register in a case-sensitive file system?

+5
source share
1 answer

Nothing was built there (although there should be, no doubt). What you can do is provide a pre-commit binding that checks that all names are in order and prevents commit if not.

This hook needs to be run only in the Linux box (although its work on Linux and Mac is simple, it's just Windows with an unmanaged default toolbox, which is problematic). You might want to add it to the side branch and give Linux configuration instructions.

You might also want to check branch names, as in git pre-commit or update hook, to stop committing with branch names with a match for word insensitivity . (Interesting: the answer to this question is mine, I forgot it.)

First, write a "conflict check" function. It is just a matter of folding sorting (so that "helloworld" and "helloWorld" are next to each other), then using uniq -di to print any duplicate (after folding) lines, duplicates:

 sort -f | uniq -di 

If this produces any conclusion, these are "bad names." Let us capture the output in a temporary file and check its size so that we can print them to standard output too:

 #! /bin/sh TF=$(mktemp) trap "rm -f $TF" 0 1 2 3 15 checkstdin() { sort -f | uniq -di > $TF test -s $TF || return 0 # if $TF is empty, we are good echo "non-unique (after case folding) names found!" 1>&2 cat $TF 1>&2 return 1 } 

Now we just need to use it in the files to be transferred, and possibly in the branch names. The first ones are listed in git ls-files , therefore:

 git ls-files | checkstdin || { echo "ERROR - file name collision, stopping commit" 1>&2 exit 1 } 

You can come up with this to use git diff-index --cached -r --name-only --diff-filter=A HEAD to check only added files, allowing continuing existing conflicts with situations, and / or trying to check things in many branches and / or commits, but this becomes difficult.

Combine the above two snippets into one script (and test), and then just copy it into an executable called .git/hooks/pre-commit .

Checking branch names is a bit more complicated. This really should happen when you create the branch name, and not when you commit it, and it is impossible to do really good work on the client - this must be done on a centralized server that has the proper global representation.

Here is a way to do this on the server in a pre-receive script, in a shell script, and not in Python (as in the linked answer). However, we need the checkstdin function, and you might want to do this with the update hook, and not with the advance hook, since you do not need to reject all push, just one branch name.

 NULLSHA=0000000000000000000000000000000000000000 # 40 0s # Verify that the given branch name $1 is unique, # even IF we fold all existing branch names' cases. # To be used on any proposed branch creation (we won't # look at existing branches). check_new_branch_name() { (echo "$1"; git for-each-ref --format='%(refname:short)' refs/heads) | checkstdin || { echo "ERROR: new branch name $1 is not unique after case-folding" 1>&2 exit 1 # or set overall failure status } } while read oldsha newsha refname; do ... any other checks ... case $oldsha,$refname in $NULLSHA,refs/heads/*) check_new_branch_name ${refname#refs/heads/};; esac ... continue with any other checks ... done 
+4
source

Source: https://habr.com/ru/post/1261299/


All Articles