我有以下用例:我希望能够使用用户 gitolite-admin
的私钥推送到 git@git.company.com:gitolite-admin
,而我想使用“我自己的”私钥推送到 git@git.company.com:some_repo
。 AFAIK,我无法使用 ~/.ssh/config
解决这个问题,因为两种情况下的用户名和服务器名都是相同的。由于我主要使用自己的私钥,因此我在 ~/.ssh/config
中为 git@git.company.com
定义了该私钥。有谁知道覆盖用于单个 git
调用的密钥的方法?
(顺便说一句:gitolite 根据密钥区分谁在进行推送,因此就访问、所有权和审计而言,user@server 字符串对于不同的用户来说是相同的,这不是问题。)
即使用户和主机相同,在~/.ssh/config
中仍然可以区分。例如,如果您的配置如下所示:
Host gitolite-as-alice
HostName git.company.com
User git
IdentityFile /home/whoever/.ssh/id_rsa.alice
IdentitiesOnly yes
Host gitolite-as-bob
HostName git.company.com
User git
IdentityFile /home/whoever/.ssh/id_dsa.bob
IdentitiesOnly yes
然后,您只需使用 gitolite-as-alice
和 gitolite-as-bob
而不是 URL 中的主机名:
git remote add alice git@gitolite-as-alice:whatever.git
git remote add bob git@gitolite-as-bob:whatever.git
笔记
您希望包含选项 IdentitiesOnly yes
以防止使用默认 ID。否则,如果您还有与默认名称匹配的 id 文件,它们将首先被尝试,因为与其他配置选项(遵守“先入先出”)不同,IdentityFile
选项追加到身份尝试。请参阅:https://serverfault.com/questions/450796/how-could-i-stop-ssh-offering-a-wrong-key/450807#450807
您可以使用 git 环境变量 GIT_SSH_COMMAND
。在您的 git 存储库下的终端中运行它:
GIT_SSH_COMMAND='ssh -i ~/.ssh/your_private_key' git submodule update --init
将 ~/.ssh/your_private_key
替换为您要使用的 ssh 私钥的路径。并且您可以将后续的 git 命令(在示例中为 git submodule update --init
)更改为 git pull
、git fetch
等其他命令。
-F /dev/null
使用 git config
配置您的存储库
git config --add --local core.sshCommand 'ssh -i <<<PATH_TO_SSH_KEY>>>'
这仅适用于您的本地存储库。
one offered above by Mark Longair 的另一种方法是使用别名,该别名将在 any 远程上运行 any git 命令,并带有备用 SSH 密钥。这个想法基本上是在运行 git 命令时切换您的 SSH 身份。
相对于其他答案中的主机别名方法的优势:
即使您无法明确指定远程,也可以使用任何 git 命令或别名。
更容易使用许多存储库,因为您只需要为每台客户端机器设置一次,而不是每台客户端机器上的每个存储库一次。
我使用了一些小脚本和一个 git 别名 admin
。这样我就可以做到,例如:
git admin push
使用备用(“admin”)SSH 密钥推送到默认远程。同样,您可以使用具有此别名的任何命令(不仅仅是 push
)。您甚至可以执行 git admin clone ...
来克隆您只能使用“管理员”密钥访问的存储库。
第 1 步:创建备用 SSH 密钥,可选择设置密码,以防您在其他人的计算机上执行此操作。
第 2 步:创建一个名为“ssh-as.sh”的脚本,该脚本运行使用 SSH 的东西,但使用给定的 SSH 密钥而不是默认密钥:
#!/bin/bash
exec ssh ${SSH_KEYFILE+-i "$SSH_KEYFILE"} "$@"
第 3 步:创建一个名为“git-as.sh”的脚本,该脚本使用给定的 SSH 密钥运行 git 命令。
#!/bin/bash
SSH_KEYFILE=$1 GIT_SSH=${BASH_SOURCE%/*}/ssh-as.sh exec git "${@:2}"
第 4 步:添加别名(使用下面的“PATH_TO_SCRIPTS_DIR”适当的名称):
# Run git commands as the SSH identity provided by the keyfile ~/.ssh/admin
git config --global alias.admin \!"PATH_TO_SCRIPTS_DIR/git-as.sh ~/.ssh/admin"
$@
周围添加双引号 -> "$@"
为了安全。
在阅读其他答案的基础上,我将以下方法拼凑在一起并使用 github 进行了测试,该方法结合了一些技术:
正确的 SSH 配置
git URL 重写
这种方法的优点是,一旦设置好,它就不需要任何额外的工作来让它正确 - 例如,您不需要更改远程 URL 或记住以不同的方式克隆东西 - URL 重写使一切正常.
~/.ssh/config
# Personal GitHub
Host github.com
HostName github.com
User git
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/github_id_rsa
# Work GitHub
Host github-work
HostName github.com
User git
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/work_github_id_rsa
Host *
IdentitiesOnly yes
~/.gitconfig
[user]
name = My Name
email = personal@personal.email
[includeIf "gitdir:~/dev/work/"]
path = ~/dev/work/.gitconfig
[url "github-work:work-github-org/"]
insteadOf = git@github.com:work-github-org/
~/dev/work/.gitconfig
[user]
email = work@work.email
只要您将所有工作存储库保存在 ~/dev/work 和其他地方的个人资料下,git 将在对服务器执行拉取/克隆/推送时使用正确的 SSH 密钥,并且它还会将正确的电子邮件地址附加到所有你的承诺。
参考:
1
2
includeIf
应该只在我认为存在 .git
目录的情况下才有效?
UseKeychain
行。欲了解更多信息:stackoverflow.com/a/47455373/2037998
从 git 2.10 开始,也可以使用 gitconfig sshCommand 设置。 Docs state:
如果设置了这个变量,当 git fetch 和 git push 需要连接到远程系统时,它们将使用指定的命令而不是 ssh。该命令与 GIT_SSH_COMMAND 环境变量的形式相同,并在设置环境变量时被覆盖。
一个使用示例是:git config core.sshCommand "ssh -i ~/.ssh/[insert_your_keyname]
在某些情况下这不起作用,因为 ssh_config 覆盖了命令,在这种情况下尝试 ssh -i ~/.ssh/[insert_your_keyname] -F /dev/null
不使用 ssh_config。
一个基于 Unix 的系统(Linux、BSD、Mac OS X),默认身份存储在目录 $HOME/.ssh 中的 2 个文件中: private key: $HOME/.ssh/id_rsa public key: $HOME/.ssh/id_rsa.pub
当您使用不带选项的 ssh
时-i
,它使用默认私钥与远程系统进行身份验证。
如果您有另一个要使用的私钥,例如 $HOME/.ssh/deploy_key,则必须使用 ssh -i ~/.ssh/deploy_key ...
这很烦人。您可以在 $HOME/.bash_profile 中添加以下行: ssh-add ~/.ssh/deploy_key ssh-add ~/.ssh/id_rsa
因此,每次您使用 ssh
或 git
或 scp
(基本上也是 ssh
)时,您不必再使用选项 -i
。
您可以在文件 $HOME/.bash_profile 中添加任意数量的键。
另一种选择是使用 ssh-ident, to manage your ssh identities。
它会根据您当前的工作目录、ssh 选项等自动加载和使用不同的密钥……这意味着您可以轻松地拥有一个工作/目录和私有/目录,最终透明地使用不同的密钥和身份与 ssh。
我在 Win7 上使用 Git Bash。以下对我有用。
在 ~/.ssh/config 或 c:/users/[your_user_name]/.ssh/config 创建一个配置文件。在文件中输入:
Host your_host.com
IdentityFile [absolute_path_to_your_.ssh]\id_rsa
我猜主机必须是一个 URL,而不仅仅是主机的“名称”或参考。例如,
Host github.com
IdentityFile c:/users/[user_name]/.ssh/id_rsa
路径也可以写成 /c/users/[user_name]/.... 格式
Giordano Scalzo 提供的解决方案也很棒。 https://stackoverflow.com/a/9149518/1738546
使用 ~/.ssh/config
的一种可能性是使用 Match
限制而不是 Host
限制。特别是 Match Exec
调用一个 shell 命令来决定是否应用声明。在 bash 中,您可以使用以下命令:
[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]
这使用 bash [
命令来验证两个字符串是否相等。在这种情况下,它正在测试字符串 git@git.company.com:gitolite-admin
是否与从 $(git config --get remote.origin.url)''
命令获得的输出相匹配。
您可以使用任何其他命令来标识 shell 所在的存储库。为此,重要将 $SHELL
变量定义到您的 shell,在我的例子中是 /bin/bash
。完整的示例将是以下 ~/.ssh/config
:
Match Exec "[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]"
IdentityFile ~/.ssh/gitolite-admin
IdentitiesOnly yes
ForwardAgent no
ForwardX11 no
ForwardX11Trusted no
Match Exec "[ git@git.company.com:some_repo = $(git config --get remote.origin.url)'' ]"
IdentityFile ~/.ssh/yourOwnPrivateKey
IdentitiesOnly yes
ForwardAgent no
ForwardX11 no
ForwardX11Trusted no
在此示例中,我假设 ~/.ssh/yourOwnPrivateKey
包含您自己的私钥,而 ~/.ssh/gitolite-admin
包含用户 gitolite-admin
的私钥。我包含了 IdentitiesOnly yes
声明,以确保只向 git 服务器提供一个密钥,如 Mark Longair 所述。其他声明只是 git 的标准 ssh 选项。
如果您有多个要与不同键一起使用的 some_repo
,则可以添加此配置。如果您在 git@git.company.com
有多个存储库,并且其中大多数使用 ~/.ssh/yourOwnPrivateKey
,则将此密钥作为主机的默认值包含在内更有意义。在这种情况下,~/.ssh/config
将是:
Match Exec "[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]"
IdentityFile ~/.ssh/gitolite-admin
IdentitiesOnly yes
Host git.company.com
IdentityFile ~/.ssh/yourOwnPrivateKey
IdentitiesOnly yes
ForwardAgent no
ForwardX11 no
ForwardX11Trusted no
请注意,顺序很重要,Host git.company.com
限制应出现在 Match Exec
一个或一个之后。
Host gitolite-as-alice
中的 Host
值(忽略 HostName
),但这种方法避免了这个问题!请注意,您还可以使用通配符来匹配:Match Exec "[[ $(git config --get remote.origin.url)'' == 'git@github.com:YourOrganization'* ]]"
Match Exec "[[ $(git config --get remote.origin.url)'' == 'git@github.com:YourOrganization'* ]]"
合作
Bash
,那么条件可以像这样简单:Match Exec "[[ $(git config --get remote.origin.url) == git@github.com:YourOrganization/* ]]"
(注意组织名称后面的斜杠,因此它不会与 YourOrganizationAnother
重叠)
要即时使用特定键:
GIT_SSH_COMMAND='ssh -i $HOME/.ssh/id_ed25519 -o IdentitiesOnly=yes -F /dev/null' git push origin c13_training_network
解释:
执行推送之前的本地 ENV var
-i 指定键
-F 强制一个空配置,所以你的全局配置不会覆盖这个临时命令
正如其他人提到的,core.sshCommand
配置可用于覆盖 SSH 密钥和其他参数。
这是一个示例,其中您有一个名为 ~/.ssh/workrsa
的备用键,并希望将它用于克隆在 ~/work
下的所有存储库。
在 ~/work 下创建一个新的 .gitconfig 文件:
[core]
sshCommand = "ssh -i ~/.ssh/workrsa"
在你的全局 git config ~/.gitconfig 中,添加:
[includeIf "gitdir:~/work/"]
path = ~/work/.gitconfig
如果您已经有默认的 ssh 密钥配置,但想对特定存储库使用不同的配置,那么这应该可以解决问题:
git config core.sshCommand "ssh -i ~/.ssh/github-personal -o IdentitiesOnly=yes -F /dev/null"
如果在 Windows 上使用 Git 的 ssh 版本,ssh 配置中的身份文件行看起来像
IdentityFile /c/Users/Whoever/.ssh/id_rsa.alice
其中 /c
代表 c:
要检查,在 git 的 bash 中做
cd ~/.ssh
pwd
https://i.stack.imgur.com/hb86h.png
为了让 git 弄清楚,它应该使用不同的 SSH 密钥,除了更改您的配置文件,如下所述:https://stackoverflow.com/a/7927828/1306884 您可能还需要清除并重新加载活动的 SSH 身份。
在 Mac 上,执行以下操作:
ssh-add -D
ssh-add ~/.ssh/id_rsa_one_that_you_want_to_use_instead
使用这两个命令,并设置 GIT URL 以匹配 ssh/config 文件的 Host
中定义的字符串,应该允许您为不同的存储库使用不同的 SSH 密钥。
例如,对于 Host work.github.com
,在克隆您的存储库 git@work.github.com:your/repository.git
时使用 work.github.com
作为 URL。
您最常在文件配置密钥 ssh 中指定:
# Default GitHub user
Host one
HostName gitlab.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/key-one
IdentitiesOnly yes
#two user
Host two
HostName gitlab.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/key-two
IdentitiesOnly yes
注意:有一种方法可以将 previous answer 中建议的 git 配置应用于目录,而不仅仅是在 repo 级别。
在我的例子中,所有项目都在 ~/work/
目录下,所以我更新了我的 gitconfig 如下:
# ~/.gitconfig
...
[includeIf "gitdir:~/work/**"]
path = "~/work/.gitconfig"
# ~/work/.gitconfig
[user]
email = amr@work.com
name = Amr Awad
sshCommand = ssh -i ~/.ssh/work
现在 ~/work/
目录中的所有存储库都使用工作密钥 ~/.ssh/work
,而无需单独配置每个存储库。
这是简单的方法:
- 从您的本地根 git 文件夹。
- 检查本地存储库的当前身份验证方法 HTTPS 或 SSH 类型。
git remote -v
Example using HTTPS:
origin https://github.com/juantorres9/SQLite_crash_cours.git (fetch)
origin https://github.com/juantorres9/SQLite_crash_cours.git (push)
Example using SSH:
origin git@github.com:juantorres9/SQLite_crash_cours.git (fetch)
origin git@github.com:juantorres9/SQLite_crash_cours.git (push)
- 设置您选择的身份验证方法,以防尚未设置。
For setting SSH
git remote set-url origin git@github.com:USERNAME/REPOSITORY.git
For setting HTTPS
git remote set-url origin https://github.com/USERNAME/REPOSITORY.git
- 再次检查,以防你想仔细检查
git remote -v
-您现在可以使用配置的方法使用 git push:fetch。
git push origin master
注意 最后但同样重要的是,请查看更新的官方文档https://docs.github.com/en/get-started/getting-started-with-git/managing-remote-repositories
git@
部分不是必需的,因为它在配置的User
行中给出。IdentityFile
行之后立即添加了另一行包含IdentitiesOnly yes
的行。似乎它传递了多个身份,其中一个被阻止访问主机。