15,067
edits
| Line 1: | Line 1: | ||
== Troubleshooting of GIT == | == Troubleshooting of GIT == | ||
=== Git Push Failed: Invalid username or token (GitHub No Longer Supports Password Authentication) === | |||
'''Problem''' | |||
Running <code>git push</code> produces the following error: | |||
<pre> | |||
remote: Invalid username or token. Password authentication is not supported for Git operations. | |||
fatal: Authentication failed for 'https://github.com/team_name/repo_name/' | |||
In a case you entered incorrect password, please | |||
update it in Keychain Access application. | |||
</pre> | |||
'''Diagnosis''' | |||
First check the current login status of the GitHub CLI: | |||
<pre> | |||
gh auth status | |||
</pre> | |||
If the token has expired, a message similar to the following will appear: | |||
<pre> | |||
github.com | |||
X Failed to log in to github.com account UserName (keyring) | |||
* Active account: true | |||
* The token in keyring is invalid. | |||
* To re-authenticate, run: gh auth login -h github.com | |||
* To forget about this account, run: gh auth logout -h github.com -u UserName | |||
</pre> | |||
You can also directly query the GitHub credentials stored in the macOS Keychain: | |||
<pre> | |||
security find-internet-password -s github.com | |||
</pre> | |||
'''Cause''' | |||
This error is typically caused by one of the following: | |||
* An old GitHub account password (rather than a token) is stored in the macOS Keychain, and Git's attempt to authenticate with that password fails. | |||
* The Personal Access Token in the <code>gh</code> keyring has expired, been revoked, or had its permissions changed. | |||
* A token or SSH key was never set up, so Git is still falling back to the legacy password authentication flow. | |||
'''Solution''' | |||
'''Re-authenticate the GitHub CLI''' | |||
<pre> | |||
gh auth login -h github.com | |||
</pre> | |||
Select the following options in order: | |||
* What is your preferred protocol for Git operations on this host? → <code>HTTPS</code> (matches the existing remote protocol) | |||
* How would you like to authenticate GitHub CLI? → <code>Login with a web browser</code> | |||
A one-time code will be displayed. Copy it and press Enter; a browser window will open the GitHub device authorization page to complete the login: | |||
<pre> | |||
! First copy your one-time code: XXXX-XXXX | |||
Press Enter to open https://github.com/login/device in your browser... | |||
✓ Authentication complete. | |||
* gh config set -h github.com git_protocol https | |||
✓ Configured git protocol | |||
✓ Logged in as UserName | |||
</pre> | |||
=== 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. | |||
=== Restoring deleted files in Git === | === Restoring deleted files in Git === | ||
| Line 379: | Line 668: | ||
so Git always uses the correct SSH key. | so Git always uses the correct SSH key. | ||
== Further Reading == | == Further Reading == | ||