[brew update]Error:homebrew-core is a shallow clone.で失敗するのを解決

4 min read読了の目安(約3900字

前提

タイトル通りbrew updateをしようとするとhomebrew-coreがshallow cloneだと出て動かなかった。
エラー文の解釈と解決方法についてのメモまとめたので以下に載せていく。
※筆者も勉強中のため間違いがありましたらご指摘いただけると幸いです!

Homebrewのバージョン

$ brew --version
Homebrew 2.6.1
Homebrew/homebrew-core (git revision 6ba53; last commit 2020-12-09)
Homebrew/homebrew-cask (git revision 02bd60; last commit 2020-12-10)

発生事象

brew updateをしようとすると下記のエラーが発生し出来ない。

$ brew update
Error: homebrew-core is a shallow clone. To `brew update` first run:
git -C "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core" fetch --unshallow
This restriction has been made on GitHub's request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-core. We don't do this for you automatically to avoid
repeatedly performing an expensive unshallow operation in CI systems (which
should instead be fixed to not use shallow clones). Sorry for the inconvenience!

エラーを解決

ここまで読んで「理屈はともかく早く治したい!」と言う方はエラー文にある通り下記のコマンドを打てば解決です。

-- 時間かかる...
$ git -C "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core" fetch --unshallow

エラーの解釈

homebrew-core is a shallow clone. To brew update first run

『homebrew-coreはshallow cloneです。先に(下記のスクリプトを)走らせてください。』とあります。

shallow cloneとはGitの機能でこれを使えば最新版のコミットのみpull[1]して来ることが出来ます。

(より正確に言えば任意の深さ(バージョン)の所までpull出来る機能です。)

※参考:How to Use Git Shallow Clone to Improve Performance

This restriction has been made on GitHub's request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-core.

続きます。『この制限はGitHubのリクエストによるものです。というのもshallow cloneの実行はツリーレイアウトやHomebrew/homebrew-coreのトラフィック量を考えるとかなりの高コストな処理になってしまうためです。』

ここからshallow cloneがダメになったのはGitHubからの要請なのだ、と理解できます。

これについてはWhy shallow clone is expensive to perform?というGitHub Discussion内に挙げられているリンク先の中でのコメントでより詳細に説明されています。下記にて筆者が重要だと思った箇所のみ抜粋します。

most of the initial clones are shallow, meaning that not the whole history is fetched, but just the top commit. But then subsequent fetches don't use the --depth=1 option. Ironically, this practice can be much more expensive than full fetches/clones, especially over the long term. It is usually preferable to pay the price of a full clone once, then incrementally fetch into the repository, because then Git is better able to negotiate the minimum set of changes that have to be transferred to bring the clone up to date.

一度shallow cloneしても後々のfetchで(depth=1オプションが使われることはないので)結局ドカンと全体が落とされる。それよりも最初にgit cloneでリポジトリ全体を取ってきて徐々にgit fetchで変化を埋めていく方がGitは得意だし負荷も低くなるとのこと。

さて、最後のエラー文を読んでいきます。

We don't do this for you automatically to avoid
repeatedly performing an expensive unshallow operation in CI systems (which
should instead be fixed to not use shallow clones). Sorry for the inconvenience!

『今回上記の措置をユーザーのため自動的に行わなかったのはCI(継続的インテグレーション)システムの中で繰り返し高コストなunshallowの処理を行うことを避けるためです。ご迷惑おかけしております<(_ _)>.』

自動で実行すると逆に負荷が大きいから手動でやってね、とのことでした。

参考

脚注
  1. pullとは簡単に言うと「リモートからローカルにコミットやファイルを引っ張ってしかもワークツリーにマージまでしてくれる」gitのコマンド ↩︎