Troubleshooting of GIT: Difference between revisions

From LemonWiki共筆
Jump to navigation Jump to search
(Created page with " == Troubleshooting of GIT == === Restoring deleted files in Git === Restoring deleted files in Git === SSH Authentication Failed: Permission denied (publickey) === '''Error Message''' After keyin the command <pre>git clone [email protected]:your-org/your-repo.git /opt/your-app</pre>, met the error message <pre> Cloning into '/opt/your-app'... [email protected]: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the...")
 
 
(3 intermediate revisions by the same user not shown)
Line 9: Line 9:
'''Error Message'''
'''Error Message'''


After keyin the command <pre>git clone [email protected]:your-org/your-repo.git /opt/your-app</pre>, met the error message
After running the command:
 
<pre>
git clone [email protected]:your-org/your-repo.git /opt/your-app
</pre>
 
you may see the following error:


<pre>
<pre>
Line 17: Line 23:


Please make sure you have the correct access rights and the repository exists.
Please make sure you have the correct access rights and the repository exists.
</pre>
A similar error may also occur when running:
<pre>
git pull
</pre>
or:
<pre>
sudo git pull
</pre>
</pre>


'''Cause'''
'''Cause'''


This error occurs when Git cannot authenticate with GitHub over SSH. This typically means the SSH key on your machine is either missing, not registered with your GitHub account, or not being picked up by the SSH agent.
This error occurs when Git cannot authenticate with GitHub over SSH.
 
Common causes include:
 
* The SSH key does not exist on the server.
* The SSH key has not been added to GitHub.
* The SSH key is added to the wrong GitHub account or the wrong repository.
* The repository is private and the key does not have access.
* The server has multiple SSH keys, but Git is using the wrong one.
* The key is a GitHub Deploy Key that belongs to another repository.
* `sudo git clone` or `sudo git pull` is being used, causing Git to use the `root` user's SSH key instead of the deploy user's SSH key.
 
For example, if you run:


'''Solutions'''
<pre>
</pre>


'''Option 1 — Configure your SSH config file'''
and see:


Add an entry to `~/.ssh/config` so Git automatically uses the correct key:
<pre>
Hi other-org/other-repo! You've successfully authenticated, but GitHub does not provide shell access.
</pre>
 
it means the current SSH key is valid, but it is linked to another repository's Deploy Key. In that case, GitHub may return:


<pre>
<pre>
Host github.com
ERROR: Repository not found.
</pre>
 
even if the target repository URL is correct.
 
'''Recommended Solution — Use a dedicated SSH alias for the project'''
 
This is the safest approach when the server has multiple GitHub Deploy Keys.
 
Assume:
 
<pre>
Deploy user: your-user
App path: /opt/your-app
Private key: /home/your-user/.ssh/id_ed25519_your_app
Public key: /home/your-user/.ssh/id_ed25519_your_app.pub
Repository: git@github.com:your-org/your-repo.git
</pre>
 
'''Step 1 — Check the key exists'''
 
<pre>
ls -l ~/.ssh/id_ed25519_your_app*
</pre>
 
Expected result:
 
<pre>
/home/your-user/.ssh/id_ed25519_your_app
/home/your-user/.ssh/id_ed25519_your_app.pub
</pre>
 
If the key does not exist, create one:
 
<pre>
ssh-keygen -t ed25519 -C "your-app-deploy-key" -f ~/.ssh/id_ed25519_your_app
</pre>
 
'''Step 2 — Add the public key to GitHub'''
 
Print the public key:
 
<pre>
cat ~/.ssh/id_ed25519_your_app.pub
</pre>
 
Add it to the target repository:
 
<pre>
GitHub Repository
→ Settings
→ Deploy keys
→ Add deploy key
</pre>
 
If the server only needs to clone or pull the repository, do not enable write access.
 
'''Step 3 — Configure SSH alias'''
 
Edit the SSH config file:
 
<pre>
nano ~/.ssh/config
</pre>
 
Add:
 
<pre>
Host github-your-app
   HostName github.com
   HostName github.com
   User git
   User git
   IdentityFile /path/to/.ssh/your_key_name
   IdentityFile ~/.ssh/id_ed25519_your_app
  IdentitiesOnly yes
</pre>
 
Fix SSH file permissions:
 
<pre>
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config ~/.ssh/id_ed25519_your_app
chmod 644 ~/.ssh/id_ed25519_your_app.pub
</pre>
 
Explanation:
 
# <code>~/.ssh</code> should be accessible only by the current user
# <code>~/.ssh/config/</code> should be readable/writable only by the current user
# <code>~/.ssh/id_ed25519_your_app</code> private key should be readable only by the current user
# <code>~/.ssh/id_ed25519_your_app.pub</code> public key can be readable by others
 
'''Step 4 — Test the SSH alias'''
 
Run:
 
<pre>
ssh -T github-your-app
</pre>
 
Expected result:
 
<pre>
Hi your-org/your-repo! You've successfully authenticated, but GitHub does not provide shell access.
</pre>
 
The message:
 
<pre>
GitHub does not provide shell access.
</pre>
 
is expected. It means SSH authentication works, but GitHub does not allow interactive shell login.
 
If the result shows another repository, for example:
 
<pre>
Hi other-org/other-repo! You've successfully authenticated, but GitHub does not provide shell access.
</pre>
 
then the alias is not using the intended key, or the key was added to the wrong repository.
 
'''Step 5 — Clone using the SSH alias'''
 
Instead of:
 
<pre>
git clone [email protected]:your-org/your-repo.git /opt/your-app
</pre>
</pre>


'''Option 2 — Pass the SSH key inline'''
use:


1. Before running `git clone`, test whether the specified SSH key can successfully authenticate with GitHub:
<pre>
git clone git@github-your-app:your-org/your-repo.git /opt/your-app
</pre>
 
If `/opt/your-app` requires root permission to create, prefer creating the directory first and assigning ownership to the deploy user:


<pre>
<pre>
ssh -T -i /path/to/.ssh/your_key_name git@github.com
sudo mkdir -p /opt/your-app
sudo chown -R your-user:your-user /opt/your-app
git clone git@github-your-app:your-org/your-repo.git /opt/your-app
</pre>
</pre>


If the key is configured correctly, you should see:
This avoids using `sudo git clone`.
 
'''Step 6 — If the repository already exists, update the remote URL'''
 
Check the current remote:


<pre>
<pre>
Hi your-org/your-app! You've successfully authenticated, but GitHub does not provide shell access.
cd /opt/your-app
git remote -v
</pre>
</pre>


`successfully authenticated` confirms the key is correctly linked to your GitHub account and you're good to proceed with `git clone`. The message `GitHub does not provide shell access` is expected — SSH is used for Git operations only, not for interactive shell login.
If it uses the default GitHub host:


2. Override the SSH command directly when cloning:
<pre>
origin  git@github.com:your-org/your-repo.git (fetch)
origin  [email protected]:your-org/your-repo.git (push)
</pre>
 
change it to use the SSH alias:
 
<pre>
git remote set-url origin git@github-your-app:your-org/your-repo.git
</pre>
 
Verify:
 
<pre>
git remote -v
</pre>
 
Expected result:
 
<pre>
origin  git@github-your-app:your-org/your-repo.git (fetch)
origin  git@github-your-app:your-org/your-repo.git (push)
</pre>
 
Then run:
 
<pre>
git pull
</pre>
 
'''Avoid using sudo with Git'''
 
Avoid:
 
<pre>
sudo git clone [email protected]:your-org/your-repo.git /opt/your-app
sudo git pull
</pre>
 
Because `sudo` runs Git as `root`, Git may use root's SSH keys instead of the deploy user's SSH keys.
 
If the app directory is owned by `root`, fix ownership instead:
 
<pre>
sudo chown -R your-user:your-user /opt/your-app
</pre>
 
Then run Git commands as the deploy user:
 
<pre>
cd /opt/your-app
git pull
</pre>
 
'''Related Issue: dubious ownership'''
 
If Git shows:
 
<pre>
fatal: detected dubious ownership in repository at '/opt/your-app'
</pre>
 
it means the current user and the repository owner do not match.
 
Check:
 
<pre>
ls -ld /opt/your-app
whoami
</pre>
 
If the app should be maintained by the deploy user, fix ownership:
 
<pre>
sudo chown -R your-user:your-user /opt/your-app
</pre>
 
Alternatively, mark the directory as safe:
 
<pre>
git config --global --add safe.directory /opt/your-app
</pre>
 
For deployment directories, fixing ownership is usually cleaner if the deploy user is expected to run `git pull`.
 
'''Alternative Solution — Pass the SSH key inline'''
 
You can also override the SSH command directly.
 
First, test the key:
 
<pre>
ssh -T -i /path/to/.ssh/your_key_name -o IdentitiesOnly=yes [email protected]
</pre>
 
Expected result:
 
<pre>
Hi your-org/your-repo! You've successfully authenticated, but GitHub does not provide shell access.
</pre>
 
Then clone:
 
<pre>
GIT_SSH_COMMAND='ssh -i /path/to/.ssh/your_key_name -o IdentitiesOnly=yes' \
  git clone [email protected]:your-org/your-repo.git /opt/your-app
</pre>
 
If you need to run this with `sudo`, preserve the environment explicitly:


<pre>
<pre>
Line 59: Line 336:
</pre>
</pre>


{{exclaim}} Notice: `-o IdentitiesOnly=yes` prevents SSH from trying other keys loaded in the agent, which can cause unexpected auth failures.
However, this is usually less clean than using an SSH alias, especially for long-term maintenance.
 
'''Notice'''
 
<pre>
-o IdentitiesOnly=yes
</pre>
 
forces SSH to use only the specified key and prevents SSH from trying other keys loaded in the agent. This is important on servers with multiple Deploy Keys.
 
'''Summary'''
 
Recommended long-term setup:
 
<pre>
# 1. Create or confirm a dedicated deploy key
ls ~/.ssh/id_ed25519_your_app*
 
# 2. Add the public key to the target GitHub repository Deploy Keys
cat ~/.ssh/id_ed25519_your_app.pub
 
# 3. Configure SSH alias
nano ~/.ssh/config
 
# 4. Test alias
ssh -T github-your-app
 
# 5. Clone or update remote using alias
git clone git@github-your-app:your-org/your-repo.git /opt/your-app
 
# or, for an existing repo
cd /opt/your-app
git remote set-url origin git@github-your-app:your-org/your-repo.git
git pull
</pre>
 
The key lesson is: when multiple Deploy Keys exist on the same server, avoid relying on `[email protected]`. Use a project-specific SSH alias such as:
 
<pre>
git@github-your-app:your-org/your-repo.git
</pre>
 
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: <ref>[https://git-scm.com/docs/git-config?utm_source=chatgpt.com Git - git-config Documentation]</ref>
 
<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 ===
 
'''Error Message'''
 
After pulling in GitHub Desktop, met the error message
 
<pre>
Fetching submodule lib
error: unable to create file feeds/example.php: File exists
Updating xxxxxxxx..xxxxxxxx
</pre>
 
'''Cause'''
 
When Git tries to update the submodule to a newer commit, it finds a local untracked file with the same name, blocking the checkout. A mid-pull failure leaves the submodule in an inconsistent state and causes a large number of unexpected unstaged changes to appear in GitHub Desktop.
 
'''Solution'''
 
Run the following command in the project root directory to force re-sync the submodule:
 
<pre>
git submodule update --init --recursive --force
</pre>
 
If it still fails, manually remove the conflicting file and retry:
 
<pre>
rm lib/feeds/example.php
git submodule update --init --recursive
</pre>
 
Enter the submodule directory and verify the status is clean:
 
<pre>
cd lib
git status
</pre>
 
The expected output should be:
 
<pre>
HEAD detached from xxxxxxxx
nothing to commit, working tree clean
</pre>
 
`nothing to commit, working tree clean` confirms the submodule has been successfully synced — return to GitHub Desktop and continue as normal. `HEAD detached` is the expected state for a submodule and does not require any action.
 
{{exclaim}} Notice: The large number of unstaged changes appearing in GitHub Desktop after a failed Pull will typically return to normal once the submodule is fixed. If unexpected changes still remain, run <code>git submodule foreach git checkout .</code> to revert all modifications inside every submodule.


== Further Reading ==
== Further Reading ==

Latest revision as of 14:54, 13 July 2026

Troubleshooting of GIT[edit]

Restoring deleted files in Git[edit]

Restoring deleted files in Git

SSH Authentication Failed: Permission denied (publickey)[edit]

Error Message

After running the command:

git clone [email protected]:your-org/your-repo.git /opt/your-app

you may see the following error:

Cloning into '/opt/your-app'...
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights and the repository exists.

A similar error may also occur when running:

git pull

or:

sudo git pull

Cause

This error occurs when Git cannot authenticate with GitHub over SSH.

Common causes include:

  • The SSH key does not exist on the server.
  • The SSH key has not been added to GitHub.
  • The SSH key is added to the wrong GitHub account or the wrong repository.
  • The repository is private and the key does not have access.
  • The server has multiple SSH keys, but Git is using the wrong one.
  • The key is a GitHub Deploy Key that belongs to another repository.
  • `sudo git clone` or `sudo git pull` is being used, causing Git to use the `root` user's SSH key instead of the deploy user's SSH key.

For example, if you run:

ssh -T [email protected]

and see:

Hi other-org/other-repo! You've successfully authenticated, but GitHub does not provide shell access.

it means the current SSH key is valid, but it is linked to another repository's Deploy Key. In that case, GitHub may return:

ERROR: Repository not found.

even if the target repository URL is correct.

Recommended Solution — Use a dedicated SSH alias for the project

This is the safest approach when the server has multiple GitHub Deploy Keys.

Assume:

Deploy user: your-user
App path: /opt/your-app
Private key: /home/your-user/.ssh/id_ed25519_your_app
Public key: /home/your-user/.ssh/id_ed25519_your_app.pub
Repository: [email protected]:your-org/your-repo.git

Step 1 — Check the key exists

ls -l ~/.ssh/id_ed25519_your_app*

Expected result:

/home/your-user/.ssh/id_ed25519_your_app
/home/your-user/.ssh/id_ed25519_your_app.pub

If the key does not exist, create one:

ssh-keygen -t ed25519 -C "your-app-deploy-key" -f ~/.ssh/id_ed25519_your_app

Step 2 — Add the public key to GitHub

Print the public key:

cat ~/.ssh/id_ed25519_your_app.pub

Add it to the target repository:

GitHub Repository
→ Settings
→ Deploy keys
→ Add deploy key

If the server only needs to clone or pull the repository, do not enable write access.

Step 3 — Configure SSH alias

Edit the SSH config file:

nano ~/.ssh/config

Add:

Host github-your-app
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_your_app
  IdentitiesOnly yes

Fix SSH file permissions:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/config ~/.ssh/id_ed25519_your_app
chmod 644 ~/.ssh/id_ed25519_your_app.pub

Explanation:

  1. ~/.ssh should be accessible only by the current user
  2. ~/.ssh/config/ should be readable/writable only by the current user
  3. ~/.ssh/id_ed25519_your_app private key should be readable only by the current user
  4. ~/.ssh/id_ed25519_your_app.pub public key can be readable by others

Step 4 — Test the SSH alias

Run:

ssh -T github-your-app

Expected result:

Hi your-org/your-repo! You've successfully authenticated, but GitHub does not provide shell access.

The message:

GitHub does not provide shell access.

is expected. It means SSH authentication works, but GitHub does not allow interactive shell login.

If the result shows another repository, for example:

Hi other-org/other-repo! You've successfully authenticated, but GitHub does not provide shell access.

then the alias is not using the intended key, or the key was added to the wrong repository.

Step 5 — Clone using the SSH alias

Instead of:

git clone [email protected]:your-org/your-repo.git /opt/your-app

use:

git clone git@github-your-app:your-org/your-repo.git /opt/your-app

If `/opt/your-app` requires root permission to create, prefer creating the directory first and assigning ownership to the deploy user:

sudo mkdir -p /opt/your-app
sudo chown -R your-user:your-user /opt/your-app
git clone git@github-your-app:your-org/your-repo.git /opt/your-app

This avoids using `sudo git clone`.

Step 6 — If the repository already exists, update the remote URL

Check the current remote:

cd /opt/your-app
git remote -v

If it uses the default GitHub host:

origin  [email protected]:your-org/your-repo.git (fetch)
origin  [email protected]:your-org/your-repo.git (push)

change it to use the SSH alias:

git remote set-url origin git@github-your-app:your-org/your-repo.git

Verify:

git remote -v

Expected result:

origin  git@github-your-app:your-org/your-repo.git (fetch)
origin  git@github-your-app:your-org/your-repo.git (push)

Then run:

git pull

Avoid using sudo with Git

Avoid:

sudo git clone [email protected]:your-org/your-repo.git /opt/your-app
sudo git pull

Because `sudo` runs Git as `root`, Git may use root's SSH keys instead of the deploy user's SSH keys.

If the app directory is owned by `root`, fix ownership instead:

sudo chown -R your-user:your-user /opt/your-app

Then run Git commands as the deploy user:

cd /opt/your-app
git pull

Related Issue: dubious ownership

If Git shows:

fatal: detected dubious ownership in repository at '/opt/your-app'

it means the current user and the repository owner do not match.

Check:

ls -ld /opt/your-app
whoami

If the app should be maintained by the deploy user, fix ownership:

sudo chown -R your-user:your-user /opt/your-app

Alternatively, mark the directory as safe:

git config --global --add safe.directory /opt/your-app

For deployment directories, fixing ownership is usually cleaner if the deploy user is expected to run `git pull`.

Alternative Solution — Pass the SSH key inline

You can also override the SSH command directly.

First, test the key:

ssh -T -i /path/to/.ssh/your_key_name -o IdentitiesOnly=yes [email protected]

Expected result:

Hi your-org/your-repo! You've successfully authenticated, but GitHub does not provide shell access.

Then clone:

GIT_SSH_COMMAND='ssh -i /path/to/.ssh/your_key_name -o IdentitiesOnly=yes' \
  git clone [email protected]:your-org/your-repo.git /opt/your-app

If you need to run this with `sudo`, preserve the environment explicitly:

sudo GIT_SSH_COMMAND='ssh -i /path/to/.ssh/your_key_name -o IdentitiesOnly=yes' \
  git clone [email protected]:your-org/your-repo.git /opt/your-app

However, this is usually less clean than using an SSH alias, especially for long-term maintenance.

Notice

-o IdentitiesOnly=yes

forces SSH to use only the specified key and prevents SSH from trying other keys loaded in the agent. This is important on servers with multiple Deploy Keys.

Summary

Recommended long-term setup:

# 1. Create or confirm a dedicated deploy key
ls ~/.ssh/id_ed25519_your_app*

# 2. Add the public key to the target GitHub repository Deploy Keys
cat ~/.ssh/id_ed25519_your_app.pub

# 3. Configure SSH alias
nano ~/.ssh/config

# 4. Test alias
ssh -T github-your-app

# 5. Clone or update remote using alias
git clone git@github-your-app:your-org/your-repo.git /opt/your-app

# or, for an existing repo
cd /opt/your-app
git remote set-url origin git@github-your-app:your-org/your-repo.git
git pull

The key lesson is: when multiple Deploy Keys exist on the same server, avoid relying on `[email protected]`. Use a project-specific SSH alias such as:

git@github-your-app:your-org/your-repo.git

so Git always uses the correct SSH key.

Git Shows Files as Modified After chmod — File Mode Changes[edit]

Problem

After running chmod +x or copying the repository between different operating systems or file systems, Git may report files as modified even though their contents have not changed:

git status

modified: scripts/deploy.sh

Running git diff may show only a file mode change:

diff --git a/scripts/deploy.sh b/scripts/deploy.sh
old mode 100644
new mode 100755

In Git file modes:

  • 100644 means a regular non-executable file.
  • 100755 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 old mode and new mode.

Diagnosis

Use the following command to check whether the reported changes are file mode changes only:

git diff --summary

Example output:

mode change 100644 => 100755 scripts/deploy.sh

You can also inspect the full diff:

git diff

If the output contains only old mode and new mode, without added or removed content lines, the change is caused by the executable bit rather than file contents.

Check the current repository setting with: [1]

git config --get core.fileMode

To see which configuration file defines the value:

git config --show-origin --get core.fileMode

Cause

The behavior is controlled by Git’s core.fileMode setting.

When it is set to true, 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 chmod +x or chmod -x.
  • 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 core.fileMode can be disabled when those mode differences should not be trusted.

Solution

To ignore executable-permission changes in the current repository, run:

git config core.fileMode false

This is the recommended scope when the issue affects only one repository. The setting is saved in that repository’s .git/config file.

To apply the setting to all repositories for the current user:

git config --global core.fileMode false

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:

git config --get core.fileMode

The expected output is:

false

Then check the repository again:

git status
git diff --summary

Permission-only changes should no longer appear as unstaged modifications.

Restore File Mode Tracking

To restore executable-bit tracking for the current repository:

git config core.fileMode true

To remove the repository-specific override and return to the global or system default:

git config --unset core.fileMode

To restore tracking globally:

git config --global core.fileMode true

When the Executable Bit Should Be Committed

Do not disable core.fileMode 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:

chmod +x scripts/deploy.sh
git add scripts/deploy.sh
git commit -m "Mark deploy script as executable"

The committed mode change will appear as:

mode change 100644 => 100755 scripts/deploy.sh

If the local file system cannot apply chmod correctly, update the Git index directly:

git update-index --chmod=+x scripts/deploy.sh
git commit -m "Mark deploy script as executable"

To remove executable status from the Git index:

git update-index --chmod=-x scripts/deploy.sh

Git provides index-level support for explicitly overriding a tracked file’s executable bit.

Icon_exclaim.gif Notice: Setting core.fileMode=false 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[edit]

Error Message

After pulling in GitHub Desktop, met the error message

Fetching submodule lib
error: unable to create file feeds/example.php: File exists
Updating xxxxxxxx..xxxxxxxx

Cause

When Git tries to update the submodule to a newer commit, it finds a local untracked file with the same name, blocking the checkout. A mid-pull failure leaves the submodule in an inconsistent state and causes a large number of unexpected unstaged changes to appear in GitHub Desktop.

Solution

Run the following command in the project root directory to force re-sync the submodule:

git submodule update --init --recursive --force

If it still fails, manually remove the conflicting file and retry:

rm lib/feeds/example.php
git submodule update --init --recursive

Enter the submodule directory and verify the status is clean:

cd lib
git status

The expected output should be:

HEAD detached from xxxxxxxx
nothing to commit, working tree clean

`nothing to commit, working tree clean` confirms the submodule has been successfully synced — return to GitHub Desktop and continue as normal. `HEAD detached` is the expected state for a submodule and does not require any action.

Icon_exclaim.gif Notice: The large number of unstaged changes appearing in GitHub Desktop after a failed Pull will typically return to normal once the submodule is fixed. If unexpected changes still remain, run git submodule foreach git checkout . to revert all modifications inside every submodule.

Further Reading[edit]