0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GitPythonでprivateなsubmoduleを取り込む

Posted at

やりたいこと

  • いろいろな事情によりGitPythonを使って、他のリポジトリをcloneしたい
  • そのリポジトリはprivateである
  • さらに、そのリポジトリの中にprivateなsubmoduleが存在する

要はprivateにリポジトリだろうがなんだろうが

git clone git@github.com:hoge/fuga.git
git submodule update --init

したいということ

やったこと

とりあえず普通にcloneする

この段階ではまだsubmoduleは空の状態になる。

import git

GITHUB_TOKEN = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
REPO_OWNER = 'hoge'
REPO_NAME = 'fuga'
DIST_PATH = 'piyo'  # リポジトリをcloneするときの名前

GIT_CLONE_URL = f'https://{GITHUB_TOKEN}@github.com/{REPO_OWNER}/{REPO_NAME}.git'

# 単にmasterをcloneするだけのとき
cloned_repo = git.Repo.clone_from(
    GIT_CLONE_URL,
    DIST_PATH)

# branch指定、sshのhost key verification無視設定、
# commit履歴深さ設定などを追加するとこんなかんじ
cloned_repo = git.Repo.clone_from(
    GIT_CLONE_URL,
    DIST_PATH
    env={'GIT_SSH_COMMAND': 'ssh -o "StrictHostKeyChecking=no"'},
    branch='poyo',
    depth=1)

submoduleがpublicであれば、 clone_from()の引数に recursive=Trueを追加するだけでよい。

gitmoduleの上書き

submoduleのcloneは、具体的には .gitmodulesに記述されたurlが使われる。
昨今わざわざID/passでgitを利用する人間は稀だと思われるので、以下のように書かれていると思われる。

.gitmodules
[submodule "poyo"]
	path = piyo
	url = git@github.com:hoge/fuga.git

つまり、このurlをtoken付きのhttpsに書き換えてあげることでsubmoduleを取得できるようになる。
clone_from()でrecursiveオプションを付与しないのは、.gitmodulesの書き換えより先に接続しようとしてしまい、権限不足でエラーが発生するためである。

単純にファイルを開いて置換処理を行い、そして保存すればよい。

# submoduleの取得に用いるURLを、sshからtoken付httpsに書き換える
gitmodules_path = os.path.join(DIST_PATH, '.gitmodules')
with open(gitmodules_path, 'r') as f:
    gitmodules = f.read()
    gitmodules = gitmodules.replace('git@github.com:', f'https://{GITHUB_TOKEN}@github.com/')
with open(gitmodules_path, 'w') as f:
    f.write(gitmodules)

git submodule update --initする

"gitpython submodule"でググるとわかるが、リリースされて10年くらいの間に実装が二転三転しており(しかも全部生きてるっぽい)、submodule周りの実装がなんか4つくらいある。

動作確認できてシンプルに実現できたやつを紹介しておく。

for submodule in cloned_repo.submodules:
    cloned_repo.git.submodule('init', submodule.name)
    cloned_repo.git.submodule('update', submodule.name)

うまくゆけばsubmoduleの中身が反映されているはず。

その他躓いたこと

公式のGitPythonリポジトリにはrequirementsとして下記のように書かれている(2021年2月5日現在)。

  • Git (1.7.x or newer)
  • Python >= 3.4

ただし、実際のところgitコマンドがsshなど他にちょいちょい依存しているので、それらも忘れないようにインストールしなければならない。
特にGitPythonを使うケースというのはdockerコンテナ内などであることが多いと思うが、そういう環境だとapk add opensshしておくみたいな「基礎的すぎて思いも寄らない箇所」への依存でコケたりするので注意が必要(一敗)。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?