LoginSignup
2
5

More than 5 years have passed since last update.

GitPythonでSSH鍵を指定してGithubにアクセスする

Posted at

プログラム内からGithub上のリポジトリにアクセスする必要がでたため、GitPythonを使用した。
大部分はチュートリアルを見て解決できたが、SSH鍵を指定しての操作で少し手間取った箇所があるため記載する。

GitでSSH鍵を指定する

今回取り組んだケースでは、まず以下の前提・要求が存在する。

  • 2つのGithubアカウントを持っている。以降、それぞれをアカウントA、アカウントBと表記する。
  • それぞれのアカウントに異なる鍵が紐付いている。以降、アカウントAの鍵を~/.ssh/id_rsaが、アカウントBの鍵を~/.ssh/id_rsa_newとする。
  • プログラム内でアカウントBのリポジトリをClone、幾つかの変更を加えた後にPushする。なおPublicリポジトリであるため、Cloneは誰でもできる。

この場合、環境に依るので一概には言えないが、アカウントAの持つリポジトリへのアクセスは問題ないことが多い。アカウントAはデフォルトのSSH鍵(~/.ssh/id_rsa)に紐付いており、Gitはデフォルトでこの鍵を使用するからだ。

一方、アカウントBを使用する場合、~/.ssh/id_rsa_newを使用することをGitに教えてやる必要がある。そのための一つの方法は、~/.ssh/configに以下のように設定することだ。

~/.ssh/config
host github-new
  user git
  hostname github.com
  identityfile ~/.ssh/id_rsa_new
  identitiesonly yes

その後、hostで指定した値をgithub.com(hostnameで指定する)の代わりに使えば、~/.ssh/id_rsa_newを使ってアクセスできる。

~/.ssh/id_rsa_newを使ってcloneする
$ git clone git@github-new:<AccountB>/<repository>.git

自分の環境で動かすだけならばこれで問題ないが、今回のプログラムは自分以外の環境でも動かす必要がある。そのため、設定よりも実行時オプションで指定できた方が良い。

GitはGIT_SSHGIT_SSH_COMMAND(GIT_SSH_COMMANDは2.3以降)という環境変数を持っている。これらはGitが使うSSHコマンドを指定することができる。実行するSSHコマンドに、上の設定ファイルと同じ内容のオプションを指定すれば、問題を解決できる。

GIT_SSH,GIT_SSH_COMMAND
# GIT_SSH
$ GIT_SSH='~/ssh_cmd' git push origin master
$ cat ~/ssh_cmd
ssh -i ~/.ssh/id_rsa_new -oIdentitiesOnly=yes "$@"

# GIT_SSH_COMMAND
$ GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa_new -oIdentitiesOnly=yes' git push origin master

(参考)http://git-scm.com/docs/git#_other

GitPythonでSSH鍵を指定する

GitPythonは、GIT_SSHGIT_SSH_COMMANDをサポートするコンテキストマネージャを定義している。

(参考)http://gitpython.readthedocs.org/en/stable/tutorial.html#handling-remotes

実行環境のGitのバージョンが2.3以上であることを前提とできなかったため、今回はGIT_SSHを使用した。
また、SSH鍵の内容を設定に既に持っていたため、鍵とコマンドをファイルに書き出して指定している。

GitPythonでのGIT_SSH,GIT_SSH_COMMAND
import git

# SSH鍵の書き出し
with open('./id_rsa_tmp', 'w') as f:
    f.write('<SSH Key>')
    os.chmod('./id_rsa_tmp', 0o600)
# SSHコマンドの書き出し
with open('./ssh_cmd', 'w') as f:
    f.write('ssh -i ../id_rsa_tmp -oIdentitiesOnly=yes "$@"')
    os.chmod('./ssh_cmd', 0o777)

# リポジトリのClone
repo = git.Repo.clone_from('accountB_repo')

# リポジトリのPush
ssh_executable = '../ssh_cmd'
with repo.git.custom_environment(GIT_SSH=ssh_executable):
    repo.remote().push('master')

注意したいのが、repo.gitcustom_environment実行時は、リポジトリのワーキングディレクトリにいるということ。
上記のコードでは、Cloneしたリポジトリ(accountB_repo)、鍵(id_rsa_tmp)、コマンド(ssh_cmd)が同一ディレクトリにある。
repo.gitcustom_environment実行時は、accountB_repoディレクトリ以下にいるため、鍵とコマンドは親ディレクトリにあることを意識して指定する。

鍵とコマンドの指定
with open('./ssh_cmd', 'w') as f:
    # 鍵は親ディクレトリにある
    f.write('ssh -i ../id_rsa_tmp -oIdentitiesOnly=yes "$@"')

# コマンドは親ディレクトリにある
ssh_executable = '../ssh_cmd'
with repo.git.custom_environment(GIT_SSH=ssh_executable):
...
2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5