I'm having the following folder structure:
ls -l
total 0
lrwxr-xr-x 1 user DF\Domain Users 23 Jun 1 13:25 name1.h -> ./../../name1.h
After executing the following commands:
chmod -x name1.h
chmod -h -x name1.h
chmod g-x name1.h
chmod o-x name1.h
The result is still the same:
ls -l
total 0
lrwxr-xr-x 1 user DF\Domain Users 23 Jun 1 13:25 name1.h -> ./../../name1.h
name1.h
is a symbolic link created with the command: ln -s
.
How can I remove the execute permission from that file on macOS in order to commit that to Git.
Another approach that doesn't work:
git update-index --chmod=-x fs_ccf_log.h
fatal: git update-index: cannot chmod -x 'src/SwiftPackage/include/name1.h'
Adding/removing the executable flag of a file in Git can be done in multiple ways and it can go wrong in some instances (example at the end of this answer). The safest way is to update it explicitly in the working directory and the index.
Here is how to remove the executable flag on a file (use +x
to add it) reliably:
chmod -x test.sh # direct change of mode in the working directory
git add --chmod=-x test.sh # stage while explicitly changing the mode
git commit
Internally, Git uses a simplified model with a limited number of recognised modes. For blobs/files, these are as follows: 100644 = normal file, 100755 = executable file, 120000 = symbolic link (reference). In consequence, Git does not support storing permissions for symlinks. This makes sense as Git follows UNIX and in Linux permissions on symlinks cannot be changed (=0777) and they are not used in any operations (reference). git update-index
fails to change the mode (executable flag) since this only works on regular files. I could not find this specific hint in the documentation but a quick look at the source code makes it clear.
On MacOS, a symlink can have permissions but they cannot be tracked by Git. It is important to note that (on MacOS) you cannot execute a linked file using a symlink with executable=true when the referenced file does not have the executable flag set.
I have seen developers doing the mistake of changing the executable flag in the staging area (index) and then re-adding the file to the index with the original mode. Overall, the desired change is not applied.
This does not work (!):
git update-index --chmod=-x test.sh
git add test.sh
git commit
After the first line, the change of the mode to 100644 is staged as we expect:
$ git diff --cached
diff --git a/test.sh b/test.sh
old mode 100755
new mode 100644
However, the mode of the file in the working directory was not changed which now shows up as an unstaged change (in the staging area the mode is 100644):
$ git diff
diff --git a/test.sh b/test.sh
old mode 100644
new mode 100755
When we now execute git add test.sh
(or any other command which stages the changes to the file), the mode is changed back to 100755. As a result, there are no staged changes to the mode of the file anymore.