Help us understand the problem. What is going on with this article?

CircleCIで.gitディレクトリをキャッシュしてチェックアウトを高速化する

More than 1 year has passed since last update.

最近でCircleCIおじさんになっているりんご(@mstssk)です。

今やっているプロジェクトのgitリポジトリが大きくなりすぎて、CircleCIでの checkout の実行に何分もかかってしまっています。
以前は2〜3分だったのが、先日は8分もかかってました。

思い切って.gitディレクトリをキャッシュしてしまうようにして、10秒前後で済むようにしてみました。

追記2019/02/19
本記事の内容を試す前に、あなたがCircleCIで使っているDockerイメージにgitとsshがインストールされているか確認しましょう。
gitとsshが無い場合、CircleCIがFallbackしてチェックアウトを行ってくれるのですが、これはイメージ上のgitとsshを使うより遅いようです。
FallbackしているかどうかはCircleCIの各ジョブのページでCheckout codeステップのログを見ればわかります。

参考記事

やった内容は、下記の公式ドキュメントとクラウドワークスさんのエンジニアブログ記事を参考にしたものです。

クラウドワークスさんの記事には、.gitのキャッシュではなく、shallow cloneすることでチェックアウトを高速化する手段が書かれていますが、私は.gitをキャッシュする方法を選択しました。
キャッシュの方法は公式ドキュメントに記載されているからというのもありますが、CircleCI上でshallow cloneするには別途GitHubのアクセストークンを用意する必要があり管理上の手間が増えてCIの管理が属人化しすぎるのを嫌ったためです。

CircleCIで .git ディレクトリをキャッシュする

実際のCircleCIの設定ファイルは以下のように記述しています。

.circleci/config.yml
version: 2
jobs:
  foobar-job:
    steps:
      # 公式ドキュメントに書いてある.gitをキャッシュするやり口
      # https://circleci.com/docs/2.0/caching/#source-caching
      - restore_cache:
          keys:
            - dot-git-cache-{{ .Environment.CACHE_KEY }}-{{ .Branch }}-{{ .Revision }}
            - dot-git-cache-{{ .Environment.CACHE_KEY }}-{{ .Branch }}-
            - dot-git-cache-{{ .Environment.CACHE_KEY }}-
      # レストア時にワーキングディレクトリがcleanじゃないことがあったのでhard reset。echoはexit code食わせるため
      - run: git reset HEAD --hard || echo ng
      - checkout
      - save_cache:
          key: dot-git-cache-{{ .Environment.CACHE_KEY }}-{{ .Branch }}-{{ .Revision }}
          paths:
            - ".git"
  • restore_cachekeys を複数指定しているのは、合致するキャッシュがなければ別コミット・別ブランチのCIのキャッシュを拾うためです。
  • {{ .Environment.CACHE_KEY }} は任意にキャッシュをクリアするため。CircleCIで CACHE_KEY という環境変数に適当な文字列を入れておいて、キャッシュをクリアしたいときに値を変えることでキャッシュのキーを変えてしまっています。
  • git reset HEAD --hard || echo ng は、レストア時にワーキングディレクトリがcleanじゃないことがあったためです。キャッシュをレストアしない場合は git reset が失敗するので、echoでexit code食わせてごまかしています。
  • .gitディレクトリをキャッシュからレストアした状態で、CircleCIの checkout を使うと、ちゃんとレストアした.gitを使ってくれるので、差分だけの取得になり高速になります。

このやり方の注意点として、変なブランチ名の付け方をしてしまったときに、キャッシュ済みのリポジトリ情報と新しいブランチ名が衝突してうまくチェックアウトできない場合があります。
具体的には feature/foo/bar というブランチを作ったあと、それを消して feature/foo というブランチを作ると、キャッシュからレストアした.gitディレクトリに feature/foo/ が既にいるので feature/foo のチェックアウトに失敗します。
めったにないことですし CACHE_KEY を変更すれば済むので、これについては特別な対応はしていません。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした