GitHubリポジトリで管理している指定したファイルをCLIで取得する

こんにちは。サービス開発室の武田です。GitHubで管理しているファイルをCLIで簡単に取得する方法を試してみました。
2024.04.10

こんにちは。サービス開発室の武田です。

GitHubで管理しているファイルをCLIで取得したいという要件がありました。手間を考えないのであれば、適当な場所にリポジトリをcloneしてコピーすればいいでしょう。でも面倒だ!ということで簡単にできる方法を探しました。

パブリックリポジトリの場合

実はパブリックリポジトリの場合はとても簡単です。例としてboto3リポジトリのpyproject.tomlを取得してみましょう。

まず対象のファイルのURLはこちらです。

  • https://github.com/boto/boto3/blob/develop/pyproject.toml

ドメインをraw.githubusercontent.comに置き換えます。

  • https://raw.githubusercontent.com/boto/boto3/develop/pyproject.toml

あとはこれを取得するだけです。

$ curl https://raw.githubusercontent.com/boto/boto3/develop/pyproject.toml
[tool.pytest.ini_options]
markers = [
    "slow: marks tests as slow",
]

[tool.isort]
profile = "black"
line_length = 79
honor_noqa = true
src_paths = ["boto3", "tests"]

[tool.black]
line-length = 79
skip_string_normalization = true

簡単ですね!

プライベートリポジトリの場合

プライベートリポジトリの場合、認証が必要なため先ほどの方法が使えません。そこで今回はghコマンドを使用することにしました。

基本的なセットアップについてはteknocatのエントリを参照してください。

使用するのはリポジトリ コンテンツAPIです。

ghコマンドで使用する場合は次のようにコマンドを実行します。

$ gh api /repos/{owner}/{repo}/contents/{path}

このコマンドの実行結果は例として次のようになります。

{
  "type": "file",
  "encoding": "base64",
  "size": 5362,
  "name": "README.md",
  "path": "README.md",
  "content": "IyBZb2d...(中略)",
  "sha": "3d21ec53a331a6f037a91c368710b99387d012c1",
  "url": "https://api.github.com/repos/octokit/octokit.rb/contents/README.md",
  "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1",
  "html_url": "https://github.com/octokit/octokit.rb/blob/master/README.md",
  "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/README.md",
  "_links": {
    "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1",
    "self": "https://api.github.com/repos/octokit/octokit.rb/contents/README.md",
    "html": "https://github.com/octokit/octokit.rb/blob/master/README.md"
  }
}

このcontentフィールドが、base64エンコードされたファイルとなっています。そのため次のようにすればファイルが取得できます。

$ gh api /repos/{owner}/{repo}/contents/{path} | jq -r '.content' | base64 --decode

この方法の注意点として、 ファイルサイズが1MB までしかサポートされません。それを超える場合contentフィールドが空になってしまいます。

そこでそれ以上のファイルの場合はdownload_urlを使用して、次のようにしてやりましょう。

$ gh api /repos/{owner}/{repo}/contents/{path} | jq -r '.download_url' | xargs curl

これで問題なく取得できます!

まとめ

ケースバイケースで次のようなコマンドで取得できます。

  • curl https://raw.githubusercontent.com/{owner}/{repo}/{path}
  • gh api /repos/{owner}/{repo}/contents/{path} | jq -r '.content' | base64 --decode
  • gh api /repos/{owner}/{repo}/contents/{path} | jq -r '.download_url' | xargs curl

あとはリダイレクトでファイルに保存するなりすればOKです。なお、contents APIを使用する方法はパブリックリポジトリでも問題なく動作するため、こちらに寄せてしまうのもありでしょう。