Homebrew で複数バージョン共存:brew extract と brew link --overwrite 実践手順

macOS や Linux で開発をしていると、「このプロジェクトは Node.js v14 が必要だけど、別のプロジェクトでは v18 を使いたい」といった状況に遭遇することがあります。Homebrew では通常、最新バージョンのパッケージしかインストールできませんが、実は brew extract
と brew link
を組み合わせることで、複数のバージョンを共存させられるのです。
この記事では、Homebrew で特定バージョンのパッケージを抽出してインストールし、必要に応じてバージョンを切り替える実践的な手順を詳しく解説します。
背景
Homebrew の基本的なバージョン管理
Homebrew は macOS や Linux で広く使われているパッケージマネージャーで、コマンド一つでソフトウェアのインストールや更新が可能です。しかし、Homebrew の基本思想は「常に最新版を提供する」ことにあり、デフォルトでは古いバージョンを直接インストールする仕組みがありません。
そのため、プロジェクトごとに異なるバージョンが必要な場合、従来は以下のような課題がありました。
Homebrew のパッケージ管理の仕組み
以下の図は、Homebrew がパッケージをどのように管理しているかを示しています。
mermaidflowchart TB
tap["Homebrew Tap<br/>(Formula リポジトリ)"]
cellar["Cellar<br/>(/opt/homebrew/Cellar)"]
link["シンボリックリンク<br/>(/opt/homebrew/bin)"]
tap -->|Formula 取得| cellar
cellar -->|brew link| link
link -->|コマンド実行| user["ユーザー"]
cellar -.->|複数バージョン| v1["package@1.0"]
cellar -.->|格納可能| v2["package@2.0"]
この図が示すように、Homebrew は Formula(パッケージ定義ファイル)から Cellar にパッケージをインストールし、シンボリックリンクを作成してユーザーがコマンドとして実行できるようにしています。
なぜ複数バージョンの共存が必要なのか
開発現場では、以下のようなシーンで複数バージョンの共存が求められます。
- レガシープロジェクトの保守: 古いバージョンの Node.js や Python が必要
- 互換性テスト: 異なるバージョンでの動作確認
- 段階的な移行: 新バージョンへの移行中に旧バージョンも並行利用
- 依存関係の制約: 特定のライブラリが特定バージョンにしか対応していない
こうしたニーズに応えるため、Homebrew では brew extract
という機能が提供されています。
課題
従来の方法の限界
Homebrew で古いバージョンをインストールしようとすると、以下のような問題に直面します。
1. 標準リポジトリには最新版しかない
通常の brew install
では、最新版のみがインストール対象です。
bash# 最新版の Node.js がインストールされる
brew install node
bash# 特定バージョンを指定してもエラーになる
brew install node@14
# Error: No available formula with the name "node@14"
2. バージョン指定された Formula が限定的
一部のパッケージには @
付きのバージョン指定 Formula がありますが、すべてのパッケージやバージョンで提供されているわけではありません。
bash# Python は一部バージョンが提供されている
brew install python@3.9
# しかし、すべてのバージョンがあるわけではない
brew install python@3.7
# Error: No available formula...
3. 手動でのバージョン管理が煩雑
以前は Git リポジトリから古い Formula を探し出して手動でインストールする方法もありましたが、非常に手間がかかります。
バージョン切り替え時の競合問題
複数バージョンをインストールした後も、以下のような課題があります。
mermaidflowchart LR
v14["Node.js 14<br/>(Cellar 内)"]
v18["Node.js 18<br/>(Cellar 内)"]
link["シンボリックリンク<br/>(/opt/homebrew/bin/node)"]
v14 -.->|競合| link
v18 -.->|競合| link
link --> user["ユーザー"]
style link fill:#ffcccc
この図が示すように、複数バージョンが Cellar に存在しても、シンボリックリンクは 1 つしか作れないため、どちらかのバージョンしか有効化できません。
そこで必要になるのが、brew link
と brew unlink
によるバージョン切り替えです。
解決策
brew extract の基本概念
brew extract
は、Homebrew の公式リポジトリから特定バージョンの Formula を抽出し、自分専用の Tap(ローカルリポジトリ)に保存するコマンドです。
以下の図は、brew extract
の仕組みを示しています。
mermaidflowchart TB
official["公式 Tap<br/>(homebrew/core)"]
history["Git 履歴<br/>(過去の Formula)"]
local["ローカル Tap<br/>(homebrew/local)"]
cellar["Cellar<br/>(実際のインストール先)"]
official --> history
history -->|brew extract| local
local -->|brew install| cellar
history -.->|例| v1["node 14.17.0 の Formula"]
history -.->|例| v2["node 16.13.0 の Formula"]
この仕組みにより、公式リポジトリの過去の状態から必要なバージョンの Formula を取り出し、ローカル環境でインストール可能にします。
brew link --overwrite の役割
brew link
は、インストール済みのパッケージにシンボリックリンクを作成し、コマンドとして実行可能にします。--overwrite
オプションを付けることで、既存のリンクを強制的に上書きできます。
# | コマンド | 説明 | 用途 |
---|---|---|---|
1 | brew link | シンボリックリンクを作成 | パッケージを有効化 |
2 | brew unlink | シンボリックリンクを削除 | パッケージを無効化 |
3 | brew link --overwrite | 既存リンクを上書き | バージョン切り替え |
4 | brew link --force | 警告を無視して強制リンク | keg-only パッケージの有効化 |
これらを組み合わせることで、複数バージョンを自在に切り替えられるようになります。
全体の作業フロー
以下は、複数バージョン共存の実現から切り替えまでの全体フローです。
mermaidflowchart TD
start["開始"] --> tap["ローカル Tap を作成"]
tap --> extract["brew extract で<br/>特定バージョンを抽出"]
extract --> install["抽出した Formula を<br/>インストール"]
install --> check["インストール確認"]
check --> switch{"バージョン切り替えが<br/>必要?"}
switch -->|はい| unlink["現在のバージョンを<br/>brew unlink"]
unlink --> linkNew["新しいバージョンを<br/>brew link --overwrite"]
linkNew --> verify["バージョン確認"]
switch -->|いいえ| done["完了"]
verify --> done
この流れを理解することで、作業の全体像が掴めます。それでは、具体的な手順を見ていきましょう。
具体例
ここでは、Node.js の複数バージョン(v14.17.0 と v18.12.0)を共存させ、切り替える手順を実践します。
ステップ 1: ローカル Tap の作成
まず、抽出した Formula を保存するためのローカル Tap を作成します。Tap は Homebrew が Formula を管理するリポジトリの単位です。
bash# ローカル Tap を作成(homebrew/local という名前)
brew tap-new homebrew/local
このコマンドを実行すると、以下のような出力が表示されます。
bash==> Created homebrew/local
/opt/homebrew/Library/Taps/homebrew/homebrew-local
ローカル Tap は /opt/homebrew/Library/Taps/homebrew/homebrew-local
に作成され、ここに Formula が保存されます。
ステップ 2: 特定バージョンの Formula を抽出
次に、brew extract
を使って公式リポジトリから Node.js v14.17.0 の Formula を抽出します。
bash# Node.js 14.17.0 の Formula を抽出
brew extract --version=14.17.0 node homebrew/local
このコマンドの各パラメータは以下の意味を持ちます。
# | パラメータ | 説明 | 例 |
---|---|---|---|
1 | --version | 抽出するバージョン | 14.17.0 |
2 | node | パッケージ名 | node |
3 | homebrew/local | 保存先の Tap | 先ほど作成したローカル Tap |
抽出が成功すると、以下のような出力が表示されます。
bash==> Searching repository history
==> Writing formula for node from revision 7a6f... to:
/opt/homebrew/Library/Taps/homebrew/homebrew-local/Formula/node@14.17.0.rb
これで、node@14.17.0
という名前の Formula がローカル Tap に作成されました。
ステップ 3: 抽出した Formula からインストール
抽出した Formula を使って、実際に Node.js v14.17.0 をインストールします。
bash# 抽出した Formula からインストール
brew install node@14.17.0
インストールには数分かかる場合があります。完了すると、以下のようなメッセージが表示されます。
bash==> Installing node@14.17.0 from homebrew/local
==> Downloading https://nodejs.org/dist/v14.17.0/node-v14.17.0.tar.gz
==> ./configure --prefix=/opt/homebrew/Cellar/node@14.17.0/14.17.0
==> make install
🍺 /opt/homebrew/Cellar/node@14.17.0/14.17.0: 3,000 files, 50MB
この時点で、Node.js v14.17.0 は Cellar にインストールされていますが、まだシンボリックリンクは作成されていません。
ステップ 4: 別バージョンも同様に抽出・インストール
同じ手順で、Node.js v18.12.0 もインストールします。
bash# Node.js 18.12.0 の Formula を抽出
brew extract --version=18.12.0 node homebrew/local
bash# インストール
brew install node@18.12.0
これで、2 つのバージョンが Cellar に共存している状態になりました。
ステップ 5: インストール確認
インストールされているバージョンを確認しましょう。
bash# インストール済みの Node.js 一覧を表示
brew list --versions | grep node
以下のような出力が表示されれば成功です。
bashnode@14.17.0 14.17.0
node@18.12.0 18.12.0
この時点では、まだどちらもリンクされていない(有効化されていない)状態です。
ステップ 6: バージョンの有効化
使いたいバージョンをリンクして有効化します。ここでは、まず v18.12.0 を有効化してみましょう。
bash# Node.js 18.12.0 をリンク(有効化)
brew link node@18.12.0 --overwrite
bash# バージョン確認
node --version
以下のように表示されれば、正しくリンクされています。
bashv18.12.0
ステップ 7: バージョンの切り替え
プロジェクトに応じてバージョンを切り替える手順を見ていきます。
現在のバージョンをアンリンク
まず、現在リンクされているバージョンを無効化します。
bash# 現在の Node.js をアンリンク
brew unlink node@18.12.0
bash# アンリンク確認
node --version
アンリンク後は、node
コマンドが見つからないか、システム標準の Node.js が表示されます。
bash-bash: node: command not found
# または
v16.14.0 # システム標準の Node.js
別バージョンをリンク
次に、使いたいバージョン(v14.17.0)をリンクします。
bash# Node.js 14.17.0 をリンク
brew link node@14.17.0 --overwrite
bash# バージョン確認
node --version
以下のように表示されれば、切り替え成功です。
bashv14.17.0
ステップ 8: 競合解決(--overwrite の活用)
既存のシンボリックリンクがある状態で brew link
を実行すると、以下のようなエラーが出る場合があります。
bashError: Could not symlink bin/node
Target /opt/homebrew/bin/node
already exists. You may want to remove it:
rm '/opt/homebrew/bin/node'
このような場合、--overwrite
オプションを付けることで強制的に上書きできます。
bash# 既存のリンクを上書きして強制的にリンク
brew link node@14.17.0 --overwrite --force
--force
オプションは、keg-only(通常リンクされないパッケージ)を強制的にリンクする場合にも使用します。
複数バージョン切り替えフローの可視化
以下の図は、実際の切り替え作業の流れを示しています。
mermaidstateDiagram-v2
[*] --> v18_linked: brew link node@18.12.0
v18_linked --> unlinked: brew unlink node@18.12.0
unlinked --> v14_linked: brew link node@14.17.0
v14_linked --> unlinked: brew unlink node@14.17.0
unlinked --> v18_linked: brew link node@18.12.0
note right of v18_linked
node --version
→ v18.12.0
end note
note right of v14_linked
node --version
→ v14.17.0
end note
note right of unlinked
node コマンドが
使用不可
end note
この図が示すように、unlink
と link
を繰り返すことで、必要に応じてバージョンを自由に切り替えられます。
エラー対応例
実際の作業では、以下のようなエラーに遭遇することがあります。
Error: No available formula with the name "node@14.17.0"
エラーコード: Formula not found
エラーメッセージ:
bashError: No available formula with the name "node@14.17.0".
Did you mean node@14, node@16 or node@18?
発生条件: brew extract
を実行せずに直接インストールしようとした場合
解決方法:
- まず
brew extract
で Formula を抽出する - その後に
brew install
を実行する
bash# 正しい手順
brew extract --version=14.17.0 node homebrew/local
brew install node@14.17.0
Error: Invalid version: 14.17.0
エラーコード: Invalid version specification
エラーメッセージ:
bashError: Invalid version: 14.17.0
The specified version does not exist in the repository history.
発生条件: 存在しないバージョンを指定した場合
解決方法:
- Node.js 公式サイトで正しいバージョン番号を確認
- GitHub の Homebrew/homebrew-core で該当バージョンの Formula が存在するか確認
- 正しいバージョン番号で再実行
Error: Permission denied
エラーコード: EACCES (Permission denied)
エラーメッセージ:
bashError: Permission denied @ apply2files - /opt/homebrew/bin/node
発生条件: リンク先のディレクトリに書き込み権限がない場合
解決方法:
- Homebrew ディレクトリの所有者を確認・修正する
bash# 所有者確認
ls -la /opt/homebrew/bin/node
bash# 所有者を現在のユーザーに変更
sudo chown -R $(whoami) /opt/homebrew
bash# 再度リンクを試行
brew link node@14.17.0 --overwrite
まとめ
Homebrew での複数バージョン共存は、brew extract
と brew link
の組み合わせで実現できます。
この記事では、以下の内容を解説しました。
- Homebrew の基本的なバージョン管理の仕組みと、複数バージョン共存が必要な理由
- 従来の方法の課題と、
brew extract
がどのように解決するか - ローカル Tap の作成から Formula の抽出、インストールまでの手順
- brew link と brew unlink を使った実際のバージョン切り替え方法
- よくあるエラーと解決策を含む実践的なトラブルシューティング
この方法を使えば、プロジェクトごとに異なるバージョンの Node.js や Python、その他のツールを柔軟に切り替えられるようになります。
ただし、頻繁にバージョンを切り替える場合は、nodenv や pyenv のような専用のバージョン管理ツールの導入も検討してみてください。これらのツールは、プロジェクトごとに自動的にバージョンを切り替える機能を提供しています。
図で理解できる要点:
- Homebrew は Cellar に複数バージョンを格納できるが、リンクは 1 つだけ
brew extract
で過去の Formula を取り出し、ローカル Tap に保存するbrew link
とbrew unlink
の繰り返しでバージョンを切り替える
関連リンク
- article
Homebrew で複数バージョン共存:brew extract と brew link --overwrite 実践手順
- article
Homebrew で arm64/x86_64 並行運用設計:二重プレフィックスと PATH 優先度の最適解
- article
Homebrew コマンドチートシート 2025:毎日使う 60 コマンド即参照リスト
- article
Homebrew を社内プロキシで使う設定完全ガイド:HTTP(S)_PROXY・証明書・ミラー最適化
- article
Homebrew vs MacPorts vs Nix 徹底比較:速度・依存解決・保守コストを実測レビュー
- article
Homebrew の仕組みを図解徹底解説:Cellar・Formula・Bottle・Tap を一気に理解【決定版】
- article
NestJS 監視運用:SLI/SLO とダッシュボード設計(Prometheus/Grafana/Loki)
- article
WebRTC AV1/VP9/H.264 ベンチ比較 2025:画質・CPU/GPU 負荷・互換性を実測
- article
MySQL アラート設計としきい値:レイテンシ・エラー率・レプリカ遅延の基準
- article
Vitest フレーク検知技術の運用:`--retry` / シード固定 / ランダム順序で堅牢化
- article
Motion(旧 Framer Motion)デザインレビュー運用:Figma パラメータ同期と差分共有のワークフロー
- article
esbuild プリバンドルを理解する:Vite の optimizeDeps 深掘り
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来