15,048
edits
| (2 intermediate revisions by the same user not shown) | |||
| Line 9: | Line 9: | ||
'''Error Message''' | '''Error Message''' | ||
After | 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 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: | |||
<pre> | |||
ssh -T [email protected] | |||
</pre> | |||
and see: | |||
<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> | |||
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: [email protected]: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 | Add it to the target repository: | ||
<pre> | <pre> | ||
Host github | 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 / | 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> | |||
use: | |||
<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> | |||
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> | |||
This avoids using `sudo git clone`. | |||
'''Step 6 — If the repository already exists, update the remote URL''' | |||
Check the current remote: | |||
<pre> | |||
cd /opt/your-app | |||
git remote -v | |||
</pre> | |||
If it uses the default GitHub host: | |||
<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> | </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> | <pre> | ||
git config --global --add safe.directory /opt/your-app | |||
</pre> | </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> | <pre> | ||
ssh -T -i /path/to/.ssh/your_key_name -o IdentitiesOnly=yes git@github.com | |||
</pre> | </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> | ||
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 === | === Git Submodule Pull Failed: unable to create file — File exists === | ||