如何为 git 指定 ssh 密钥文件

如果你在运行 ssh 命令时想指定一个密钥文件,一种很简便的方法就是使用 -i 选项。

ssh -i ~/.ssh/thatuserkey.pem [email protected]

这样非常干净利索。既简单、优雅,又十分直观。对 git 命令,我也想这么做:

git -i ~/.ssh/thatuserkey.pem clone [email protected]:/git/repo.git

然而,git 命令并没有这样的 -i 选项。真糟糕!

我找了很久都没找到类似的解决办法。我只能想到如下两种备选方案:

  1. 使用 GIT_SSH 环境变量
  2. 使用包裹脚本(wrapper script)

备选1:使用 GIT_SSH 环境变量

此方案中,你可以这样来为 git 命令指定一个密钥文件:

PKEY=~/.ssh/thatuserkey.pem git clone [email protected]:/git/repo.git

其中,~/.ssh/thatuserkey.pem 就是你想使用的密钥文件。

为了能让这正常运行,还需要进行一些预配置。首先,要创建包含如下内容的脚本 ~/ssh-git.sh


#!/bin/sh if [ -z "$PKEY" ]; then # if PKEY is not specified, run ssh using default keyfile ssh "$@" else ssh -i "$PKEY" "$@" fi

这个脚本必须是可执行的,所以需要对它执行 chmod +x

接下来,需要把 GIT_SSH 的值设置为指向上述脚本的路径。并且这个变量需要导出到 shell 环境。

export GIT_SSH=~/ssh-git.sh

现在,你每次运行 git 命令时,用 PKEY 指定的密钥文件就会传递给用 GIT_SSH 指定的脚本。这就会让 git 命令使用该密钥文件进行连接。

PKEY=~/.ssh/thatuserkey.pem git clone [email protected]:/git/repo.git

从此,每次运行 git 命令时,只需设置 PKEY 变量,你就可以随意使用你想要的密钥文件。1

如果你在运行 git 命令时未设置 PKEY , GIT_SSH 脚本仍然会被执行,因为它已经被导出到 shell 环境中了。但脚本会自动判断,如果没有设置 PKEY 就不会使用 -i 选项,这样 git 仍然会使用默认密钥文件运行。

在把 PKEY 导出到 shell 环境中时需要谨慎一些,因为无论它被设置成什么值,GIT_SSH 脚本都会使用它,即使你并没有在 git 命令里指定它。把 GIT_SSH 导出到 shell 环境中会带来另一个问题,就是 git 在运行时总会使用它。因此你需要时刻提醒自己你设置了它。你可以在每次运行 git 命令时设置 GIT_SSH 以防止它被导出到 shell 环境,代价就是整个命令将会更长。

设置 PKEY 的用法虽然可行,但在 git 命令中设置 PKEY 总觉得不那么常规。2

如果你也这么认为,那这里还有另一个备选项。

备选2:使用包裹脚本

git 命令的 -i 选项非常工整且优雅。你可以用 -i 选项来提供你想要使用的密钥文件。如果你没用这个选项,ssh 就会转而用默认的密钥文件。

如果要对 git 命令也是用 -i 选项,你就需要写个包裹脚本。包裹脚本可以让我们以我们想要的方式来设置用法,也就是模拟 ssh 的 -i 选项。

用法应该差不多像这样:

git.sh -i ~/.ssh/thatuserkey.pem clone [email protected]:/git/repo.git

其中的 git.sh 就是我们的包裹脚本。

你只需要创建这个脚本,然后把它放到你的 PATH 路径下就搞定了。

你可以直接在这里下载或直接拷贝下面的代码:


#!/bin/bash # The MIT License (MIT) # Copyright (c) 2013 Alvin Abad if [ $# -eq 0 ]; then echo "Git wrapper script that can specify an ssh-key file Usage: git.sh -i ssh-key-file git-command " exit 1 fi # remove temporary file on exit trap 'rm -f /tmp/.git_ssh.$$' 0 if [ "$1" = "-i" ]; then SSH_KEY=$2; shift; shift echo "ssh -i $SSH_KEY \$@" > /tmp/.git_ssh.$$ chmod +x /tmp/.git_ssh.$$ export GIT_SSH=/tmp/.git_ssh.$$ fi # in case the git command is repeated [ "$1" = "git" ] && shift # Run the git command git "$@"

这个脚本会优雅的处理失败的情况。如果你没指定 -i 选项,它会使用默认密钥文件来运行 git 。

这个包裹脚本使用了与 GIT_SSH 相同的原理。但与手动预配置不同的是,这个包裹脚本会在每次运行真正的 git 命令之前,临时把所有这些设置好。

其他备选项

还有其他方法可以让 git 命令使用不同的密钥文件。那就是使用 $HOME/.ssh/config 文件来为你想要连接的不同的主机映射不同的密钥文件(译者注:请参考这里)。但这种方法不能让你在运行 git 命令时任意的选择密钥文件。那些密钥文件必须得提前在配置文件中定义好才行。

你还可以用 ssh-agent 来把你想用的密钥文件加进去。我还写了一个基于 ssh-agent 的支持 -i 选项的包裹脚本。事实证明,它比 GIT_SSH 的方式还复杂。我可能还会写篇博客来展示一下那种方式是怎么搞的。

在所有这些不同的方法中,并没有哪种更好。这完全要看你使用的环境和你的个人喜好。

Alvin

注:本文翻译自 How to specify an ssh-key file with the Git command

相关文章:如何向 git 传递 ssh 选项


  1. 在我的工作流中,我比较喜欢这种控制。因为对于不同的服务器我会使用不同的密钥文件。对工作上的服务器我用一个不同的密钥,对我自己的服务器以及一些公开网站(比如 GitHub)我也用不同的密钥。就好比密码一样,你 Facebook 上的密码肯定和你银行账户的密码不一样。 ↩︎

  2. 就我个人而言,在我习惯了这种用法之后,我觉得这样也还算不错。我运行着很多脚本和命令需要设置环境变量。我不喜欢这种把它们都导出到 shell 环境中到处传播的方式。所以,我都是在命令行中指定它们。 ↩︎

Creative Commons License Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 International license .