はじめに
ある日、見慣れないエラーでサーバーへの自動デプロイが失敗。
Command failed: git pull origin develop
error: Your local changes to the following files would be overwritten by merge:
package-lock.json
なぜか git pull が失敗し、サーバー上で誰も触っていないはずの package-lock.json が変更されている。なぜ…?
この記事では、実際に遭遇した失敗体験をもとに、
-
npm installとnpm ciの違い - CI/CDでの正しい依存関係インストール手法
をまとめます。
エラーの正体
自動化したデプロイサーバーで、手動で触っていないのに package-lock.json が変化していることに気づく。
調査の結果、デプロイスクリプト内の npm install コマンドが問題の根源でした。
// ...デプロイスクリプトの一部
console.log('依存関係をインストールします');
execSync('npm install'); // ← こいつが犯人!
なぜnpm installが問題なのか?
-
npm installは主に開発環境向けのコマンド -
package.jsonとpackage-lock.jsonの内容に差異がある場合、
依存関係を解決するためにpackage-lock.jsonを勝手に更新してしまう - サーバーでこれを実行すると…
-
npm installがpackage-lock.jsonを更新 - 未コミットの変更がサーバー上に発生
- 次回の
git pullでコンフリクト→デプロイ失敗
-
ということが起きます。
npm installとnpm ciの違い比較
| 比較項目 | npm install | npm ci |
|---|---|---|
| 主な用途 | 開発環境 | CI/CD環境・自動化 |
| package-lock.json | 状況で自動更新 | 絶対に更新しない |
| node_modules | 既存を更新 | 完全削除して再生成 |
| 速度 | 遅い場合あり | 一般的に高速 |
| 個別パッケージ追加 | できる | できない |
| lockファイル必須 | 必須でない | 必須 |
| 整合性チェック | ゆるい | 厳格・ズレはエラー |
| ロックファイル書込 | ありうる | 絶対しない |
それぞれの使いどころ
-
npm install
- ローカル開発で新しいパッケージ追加や更新時に使う
-
package.json/package-lock.jsonの変更を許容したいとき
-
npm ci
- CI/CDや自動デプロイ、テスト環境、本番環境
- 「ロックファイル通りの状態を正確に再現したい時」
-
node_modulesを必ずクリーンにしたい時
失敗から学ぶ「npm ci」への切り替え
自分の失敗談
私は「npm install ならどこでも動くだろう」と思い、CI/CDスクリプトにも安易に使っていました。しかし、
- 意図せず
package-lock.jsonがサーバー上で更新 - pullできずデプロイ失敗
- サーバーで手動修正して対応…
という事故を経験しました。
解決策
# 修正前
npm install
# 修正後
npm ci
CI/CDスクリプトやYAMLファイル内で npm install → npm ci に置き換えるだけです。
これだけで、「サーバー上で未コミットの変更が発生しpull失敗」というトラブルが消えました。
npm install の際に依存関係に影響するフラグ(例: --legacy-peer-deps や --install-links)を使用している場合、npm ci を実行する際も同じフラグを渡しましょう。
まとめ
- 開発環境:npm install を使う
- パッケージ追加・更新時など柔軟性重視
- CI/CDや自動デプロイ:npm ci を使う
- 再現性・安定性重視。lockファイル通り厳格にインストール
この記事が何らかのお役に立てば幸いです。
参考