15,049
edits
| Line 379: | Line 379: | ||
so Git always uses the correct SSH key. | so Git always uses the correct SSH key. | ||
=== Git Shows Files as Modified After chmod — File Mode Changes === | |||
'''Problem''' | |||
After running <code>chmod +x</code> or copying the repository between different operating systems or file systems, Git may report files as modified even though their contents have not changed: | |||
<pre> | |||
git status | |||
modified: scripts/deploy.sh | |||
</pre> | |||
Running <code>git diff</code> may show only a file mode change: | |||
<pre> | |||
diff --git a/scripts/deploy.sh b/scripts/deploy.sh | |||
old mode 100644 | |||
new mode 100755 | |||
</pre> | |||
In Git file modes: | |||
* <code>100644</code> means a regular non-executable file. | |||
* <code>100755</code> means a regular executable file. | |||
Git records the executable bit as part of the tracked file metadata. Therefore, adding or removing executable permission can appear as a modification even when the file contents are identical. Git’s diff format explicitly reports these changes as <code>old mode</code> and <code>new mode</code>. | |||
'''Diagnosis''' | |||
Use the following command to check whether the reported changes are file mode changes only: | |||
<pre> | |||
git diff --summary | |||
</pre> | |||
Example output: | |||
<pre> | |||
mode change 100644 => 100755 scripts/deploy.sh | |||
</pre> | |||
You can also inspect the full diff: | |||
<pre> | |||
git diff | |||
</pre> | |||
If the output contains only <code>old mode</code> and <code>new mode</code>, without added or removed content lines, the change is caused by the executable bit rather than file contents. | |||
Check the current repository setting with: | |||
<pre> | |||
git config --get core.fileMode | |||
</pre> | |||
To see which configuration file defines the value: | |||
<pre> | |||
git config --show-origin --get core.fileMode | |||
</pre> | |||
'''Cause''' | |||
The behavior is controlled by Git’s <code>core.fileMode</code> setting. | |||
When it is set to <code>true</code>, Git checks whether the executable bit in the working tree differs from the mode stored in the Git index. This can create unexpected changes when: | |||
* A file was modified using <code>chmod +x</code> or <code>chmod -x</code>. | |||
* A repository was copied between Linux, macOS, Windows, a network drive, or another file system with different permission behavior. | |||
* An archive, synchronization tool, or shared folder changed executable permissions. | |||
* A container or deployment process rewrote file modes. | |||
Git’s documentation notes that some file systems may not reliably preserve executable-bit information, which is why <code>core.fileMode</code> can be disabled when those mode differences should not be trusted. | |||
'''Solution''' | |||
To ignore executable-permission changes in the current repository, run: | |||
<pre> | |||
git config core.fileMode false | |||
</pre> | |||
This is the recommended scope when the issue affects only one repository. The setting is saved in that repository’s <code>.git/config</code> file. | |||
To apply the setting to all repositories for the current user: | |||
<pre> | |||
git config --global core.fileMode false | |||
</pre> | |||
The global setting is stored in the user-level Git configuration and acts as a fallback unless a repository overrides it. | |||
Verify the effective value: | |||
<pre> | |||
git config --get core.fileMode | |||
</pre> | |||
The expected output is: | |||
<pre> | |||
false | |||
</pre> | |||
Then check the repository again: | |||
<pre> | |||
git status | |||
git diff --summary | |||
</pre> | |||
Permission-only changes should no longer appear as unstaged modifications. | |||
'''Restore File Mode Tracking''' | |||
To restore executable-bit tracking for the current repository: | |||
<pre> | |||
git config core.fileMode true | |||
</pre> | |||
To remove the repository-specific override and return to the global or system default: | |||
<pre> | |||
git config --unset core.fileMode | |||
</pre> | |||
To restore tracking globally: | |||
<pre> | |||
git config --global core.fileMode true | |||
</pre> | |||
'''When the Executable Bit Should Be Committed''' | |||
Do not disable <code>core.fileMode</code> merely to hide a legitimate permission change. | |||
For shell scripts, deployment scripts, Git hooks, command-line tools, and other files that must be executable after checkout, record the executable bit in Git intentionally: | |||
<pre> | |||
chmod +x scripts/deploy.sh | |||
git add scripts/deploy.sh | |||
git commit -m "Mark deploy script as executable" | |||
</pre> | |||
The committed mode change will appear as: | |||
<pre> | |||
mode change 100644 => 100755 scripts/deploy.sh | |||
</pre> | |||
If the local file system cannot apply <code>chmod</code> correctly, update the Git index directly: | |||
<pre> | |||
git update-index --chmod=+x scripts/deploy.sh | |||
git commit -m "Mark deploy script as executable" | |||
</pre> | |||
To remove executable status from the Git index: | |||
<pre> | |||
git update-index --chmod=-x scripts/deploy.sh | |||
</pre> | |||
Git provides index-level support for explicitly overriding a tracked file’s executable bit. | |||
{{exclaim}} Notice: Setting <code>core.fileMode=false</code> does not change the actual operating-system permissions and does not rewrite previously committed file modes. It only tells Git not to treat executable-bit differences in the working tree as modifications. Use a repository-level setting unless the same problem consistently affects all repositories on the machine. | |||
=== Git Submodule Pull Failed: unable to create file — File exists === | === Git Submodule Pull Failed: unable to create file — File exists === | ||