1. Overview

In this tutorial, we’ll learn how Git tracks the permission bit of a file. Then, we’ll understand the Git configuration to ignore file mode changes within the repository.

2. File Mode Changes

In Linux, every file has a file mode that represents the read, write, and execute permissions different groups of users have on the file. Out of the three different permissions, Git tracks the changes to the executable permission bit in its corresponding Git object.

For example, let’s say we have a script.sh file in our Git repository with initial permission bits of 444, which is read-only by everyone on the system:

$ ls -l script.sh
-rw-r--r-- 1 bob bob 0 Nov 12 03:10 script.sh

Now, we change the permission bits to 744 using chmod. The permission 744 means that the file is readable, writable, and executable by the owner and read-only for the rest of the users on the system:

$ chmod 744 script.sh
ls -l script.sh
-rwxr--r-- 1 bob bob 0 Nov 12 03:10 script.sh

Running git diff in the repository now shows us that Git has picked up on the permission change:

$  git diff script.sh
diff --git a/script.sh b/script.sh
old mode 100644
new mode 100755

We should note that the diff shows that the new mode recorded is 755. This is different from the 744 permission bits we have on our file. The reason for this is that Git doesn’t store the entire set of permission bits for the executable.

In Git, each object only has three possible permission bits: 100644 which stands for a normal file, 100755 to represent an executable file, and finally 120000 which stands for a symbolic link.

3. Ignoring File Mode Changes With Configuration

To make Git ignore all the file mode changes, we can set the core.fileMode configuration to false using git config:

$ git config core.fileMode false

Additionally, we can make that configuration a default for every repository in the system by passing the –global flag:

$ git config --global core.fileMode flag

After we’ve configured the core.fileMode to false, let’s rerun the git diff command again. Specifically, we want to observe the effect of the configuration on permission mode changes:

$ ls -l script.sh
-rwxr--r-- 1 root root 0 Nov 12 03:16 script.sh
$ git ls-files --stage
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0       script.sh
$ git diff script.sh
$

The first command shows the current permission bits of script.sh using ls -l. The output shows us that the file is executable by the owner. Then, we do a sanity check by printing the permission bits of the file as tracked by Git using the git ls-files –stage. We can see that it’s having a value of 100644, which means it’s not executable.

Then, running git diff shows an empty diff despite the change in the executable permission bit in the script.sh. That’s because by setting core.fileMode to false, we are essentially stopping Git from tracking the file mode changes in our repository.

4. Conclusion

In this article, we first learned that Git tracks executable permission bit change. Then, we looked at the configuration to make Git ignore such changes in the repository. Finally, we’ve seen the configuration in effect to prove that Git is indeed ignoring the executable permission bit change.