Homebrew долго обновляется: brew update и установка без ожидания

, 7 мин чтения

Вы набираете brew install jq, а вместо установки видите ==> Auto-updating Homebrew... и ждёте. Иногда минуту, иногда дольше. Бывает и так, что brew update висит вовсе без вывода. Разберём, что Homebrew делает в этот момент, как найти медленный шаг и какие настройки убирают ожидание, не превращая систему в набор устаревших пакетов.

Что происходит при brew update

С версии 4.0 Homebrew по умолчанию не держит на диске локальные копии больших репозиториев homebrew/core и homebrew/cask. Вместо этого он скачивает JSON-описания формул и кастов с formulae.brew.sh, а с версии 4.1 ещё и проверяет подпись этих файлов. Поэтому обычный brew update сейчас состоит из трёх частей:

  • обновление самого Homebrew: это git-репозиторий Homebrew/brew на GitHub;
  • загрузка свежих JSON-файлов API, если локальные устарели;
  • git fetch для каждого стороннего tap, который вы когда-то подключили через brew tap.

Готовые бинарные пакеты (bottles) скачиваются уже при установке, по умолчанию из GitHub Packages, то есть с ghcr.io. Отсюда первое правило диагностики. Если долго идёт обновление, ищите причину в трёх пунктах выше. Если обновление прошло быстро, а тянется установка, смотрите на загрузку bottles или на сборку из исходников.

Найдите медленный шаг

Запустите обновление с подробным выводом:

brew update --verbose

Флаг --verbose печатает проверяемые каталоги и выполняемые git-операции, поэтому видно, на каком репозитории всё замирает. Если этого мало, brew update --debug покажет трассировку всех shell-команд. Для загрузок добавьте переменную HOMEBREW_CURL_VERBOSE=1: Homebrew передаст curl флаг --verbose, и вы увидите каждый HTTP-запрос и момент, где соединение остановилось.

Засеките время командой time brew update и запустите её дважды подряд. Второй запуск должен пройти почти мгновенно, потому что обновлять уже нечего. Если и он долгий, дело не в объёме обновлений, а в соединении или в каком-то из tap.

Затем проверьте общее состояние установки:

brew doctor
brew config
brew tap

brew doctor находит типичные проблемы конфигурации, в том числе лишние локальные tap. brew config показывает версию, префикс установки и заданные переменные HOMEBREW_*. brew tap выводит все подключённые tap. Каждый из них при обновлении опрашивается отдельно, и один заброшенный репозиторий способен затормозить всё обновление.

Лишние локальные копии homebrew/core и homebrew/cask

Если Homebrew ставился давно, на диске могли остаться полные клоны homebrew/core и homebrew/cask. При установке через API они не нужны, но занимают место и тоже обновляются. Если вы не разрабатываете формулы, удалите их:

brew untap homebrew/core homebrew/cask

Формулы и касты продолжат ставиться через API. Заодно пройдитесь по выводу brew tap: если какой-то сторонний tap давно не нужен, brew untap владелец/репозиторий уберёт одну git-операцию из каждого обновления.

Отдельно проверьте, не задана ли у вас переменная HOMEBREW_NO_INSTALL_FROM_API. Она возвращает старое поведение: Homebrew работает с локальными git-копиями homebrew/core и homebrew/cask, которые обновляются заметно дольше. Кроме того, с этой переменной интервал автообновления по умолчанию сокращается до пяти минут. Включать её стоит только для разработки формул.

Автообновление перед install

Перед brew install, brew upgrade и brew tap Homebrew сам запускает обновление, если с прошлого прошло достаточно времени. По умолчанию это 24 часа, а если вы запускали команды для разработчиков, интервал сокращается до часа. Поведение настраивается переменными окружения:

ПеременнаяЧто делает
HOMEBREW_NO_AUTO_UPDATE=1полностью отключает автообновление перед командами
HOMEBREW_AUTO_UPDATE_SECS=604800запускает автообновление не чаще раза в неделю, значение в секундах
HOMEBREW_API_AUTO_UPDATE_SECSзадаёт, как часто проверять свежесть данных API, по умолчанию 450 секунд
HOMEBREW_NO_ENV_HINTS=1убирает из вывода подсказки про эти переменные

Добавьте выбранный вариант в ~/.zshrc или ~/.bashrc:

export HOMEBREW_AUTO_UPDATE_SECS=604800
export HOMEBREW_NO_ENV_HINTS=1

Полное отключение удобно в скриптах и CI, где важна предсказуемость. На рабочей машине разумнее увеличить интервал: с выключенным автообновлением легко забыть про brew update и месяцами ставить старые версии. Для разового запуска профиль править не нужно: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq.

Ни одна из этих переменных не мешает обновляться вручную. Удобная привычка: отключить автообновление и раз в неделю, когда есть время подождать, запускать brew update, затем brew outdated, чтобы увидеть устаревшие пакеты, и brew upgrade. Так ожидание переезжает из момента, когда вам срочно нужен пакет, в момент, который вы выбрали сами. На Linux все перечисленные переменные работают так же.

Bottles и сборка из исходников

Иногда медленно идёт не обновление, а сама установка. Если в выводе мелькают ./configure, make или cmake, Homebrew собирает пакет из исходников вместо загрузки готового bottle. Так бывает в трёх случаях:

  • Для вашей версии macOS или архитектуры bottle не опубликован. Homebrew прекратил сборку новых bottles для Intel-маков, поэтому на них компиляция встречается всё чаще.
  • Homebrew установлен в нестандартный каталог. Стандартные префиксы: /opt/homebrew на Apple Silicon, /usr/local на Intel, /home/linuxbrew/.linuxbrew на Linux.
  • Вы сами попросили сборку флагом --build-from-source или ставите версию --HEAD.

Проверить, есть ли готовый пакет, можно через brew info <формула>: в строке с версией будет пометка (bottled). Текущий префикс показывает brew --prefix. Если компиляция происходит из-за нестандартного каталога, надёжнее один раз переустановить Homebrew в стандартный, чем каждый раз ждать сборки. Для сборки из исходников нужны Command Line Tools, их ставит команда xcode-select --install.

Медленные загрузки и обрывы

Если bottles и JSON-файлы скачиваются медленно или загрузка обрывается на середине, помогут настройки curl, через который Homebrew качает файлы:

  • HOMEBREW_CURL_RETRIES задаёт число повторов, которое передаётся в curl --retry. По умолчанию 3, на нестабильной сети поставьте 5 или больше.
  • HOMEBREW_DOWNLOAD_CONCURRENCY управляет параллельными загрузками. В свежих версиях по умолчанию стоит auto: соединений вдвое больше, чем ядер процессора. Если роутер или прокси плохо переносят много одновременных соединений, поставьте 1, и файлы будут качаться по очереди.
  • brew fetch <формула> заранее скачивает bottle или исходники в кэш. Удобно, когда хорошее соединение есть сейчас, а установка понадобится позже.

После установки Homebrew по умолчанию запускает очистку, в выводе появляется строка с brew cleanup. Раз в 30 дней очистка полная и может занять заметное время. Если эта пауза мешает, переменная HOMEBREW_NO_INSTALL_CLEANUP=1 отключает автоматическую очистку. Тогда запускайте brew cleanup вручную, когда удобно.

Кэш и место на диске

Скачанные bottles и исходники лежат в кэше. Посмотреть путь и размер:

brew --cache
du -sh "$(brew --cache)"

Очистка:

brew cleanup -n           # показать, что будет удалено
brew cleanup              # удалить старые версии и устаревшие файлы кэша
brew cleanup --prune=all  # удалить все файлы кэша

При обычной очистке Homebrew удаляет загрузки старых версий и файлы кэша старше 120 дней, этот срок задаёт HOMEBREW_CLEANUP_MAX_AGE_DAYS. Свежие загрузки актуальных версий остаются, поэтому повторная установка того же пакета пройдёт без нового скачивания. Полную очистку с --prune=all делайте, когда действительно нужно место.

Зеркала: HOMEBREW_API_DOMAIN и HOMEBREW_BOTTLE_DOMAIN

Homebrew умеет брать данные с зеркал. Для этого в официальной документации описаны четыре переменные:

ПеременнаяЧто заменяетПо умолчанию
HOMEBREW_API_DOMAINJSON API с описаниями формул и кастовhttps://formulae.brew.sh/api
HOMEBREW_BOTTLE_DOMAINзагрузку bottles и их манифестовhttps://ghcr.io/v2/homebrew/core
HOMEBREW_BREW_GIT_REMOTEgit-репозиторий самого Homebrewhttps://github.com/Homebrew/brew
HOMEBREW_CORE_GIT_REMOTEgit-репозиторий homebrew/corehttps://github.com/Homebrew/homebrew-core

Если нужного файла на зеркале API или bottles временно нет, Homebrew берёт его с основного адреса. Сами зеркала поддерживают сторонние организации, обычно университеты и хостинги, и у каждого своя инструкция с точными адресами. Копируйте значения оттуда, а не из случайных форумов.

Помните о доверии. Документация Homebrew прямо предупреждает, что зеркалу git-репозиториев вы доверяете так же, как самому Homebrew. Подключайте только зеркала, в которых уверены, и убирайте переменные, когда зеркало перестало быть нужным: отставшее или медленное зеркало само становится причиной задержек.

Если --verbose показывает, что время уходит на соединение с github.com, formulae.brew.sh или ghcr.io, а не на работу самого Homebrew, дело в маршруте до этих серверов. Здесь помогает защищённое подключение через ближайшую к ним локацию.

Коротко

  • Найдите медленный шаг: brew update --verbose, затем brew doctor и brew tap.
  • Удалите ненужные локальные копии командой brew untap homebrew/core homebrew/cask, если не разрабатываете формулы.
  • Не держите включённой HOMEBREW_NO_INSTALL_FROM_API без причины.
  • Задайте HOMEBREW_AUTO_UPDATE_SECS=604800, а в CI используйте HOMEBREW_NO_AUTO_UPDATE=1.
  • Если идёт компиляция, проверьте пометку (bottled) в brew info и префикс через brew --prefix.
  • На нестабильной сети увеличьте HOMEBREW_CURL_RETRIES, при сбоях параллельной загрузки поставьте HOMEBREW_DOWNLOAD_CONCURRENCY=1.
  • Зеркала подключайте только проверенные и только через документированные переменные.
  • Кэш смотрите командой brew --cache, чистите через brew cleanup.

Стабильный канал для работы

Один ключ, 20 стран, до 5 устройств на Standard. Возврат в течение 7 дней.

Все тарифы