8.

Git「Unlink of file failed」の原因(Windows ファイルロック)と対処

編集
この記事の要点
  • Unlink of file failed は Windows で Git がファイル削除に失敗したときのプロンプト
  • 原因: 他プロセス(IDE、エディタ、アンチウイルス、エクスプローラー)がファイルをロックしている
  • 対処: エディタを閉じる → y で再試行、または git clean -fd で強制クリーンアップ
  • Process Explorerhandle.exe でロックしているプロセスを特定可能
  • WSL / Docker のマウント、Visual Studio、IntelliJ、VS Code が頻出原因

このエラーの概要

Windows で git checkoutgit pullgit cleangit rebase 実行中にこのプロンプトが出ます:

warning: unable to unlink 'vendor/bin/phpunit': Permission denied
Unlink of file 'vendor/bin/phpunit' failed. Should I try again? (y/n)

「ファイルを削除できなかった、もう一度試すか?」と聞かれており、他のプロセスがそのファイルを開いている / ロックしていることが原因です。Linux / Mac では削除中のファイルもプロセスは保持できますが、Windows は厳格にロックを敷くため発生します。

原因の切り分け

原因プロセス具体例
IDE / エディタVS Code / IntelliJ / Visual Studio / PhpStorm / Sublime
言語ランタイムnode.exe (nodemon)、php.exe (artisan serve)、python.exe
ビルドツールwebpack-dev-server、vite、gulp、tsc --watch
アンチウイルスWindows Defender、ESET、Symantec の常時スキャン
エクスプローラー該当フォルダを開いている / プレビュー
WSL / DockerWSL2 / Docker Desktop がマウント中
OneDrive / Dropbox同期中ロック

対処1: プロンプトに答える前にロックを解除

  1. VS Code / IntelliJ 等のエディタをすべて閉じる(または該当ファイルのタブのみ)
  2. 開いているターミナルの npm run dev / php artisan serve を停止(Ctrl + C
  3. エクスプローラーで該当フォルダを閉じる
  4. プロンプトで y を押して再試行

対処2: ロックしているプロセスを特定

# Sysinternals handle.exe をダウンロード
# https://learn.microsoft.com/sysinternals/downloads/handle

# どのプロセスがファイルを開いているか
.\handle.exe "C:\path\to\file"

# 結果例
# node.exe         pid: 12345  type: File  C:\path\to\file
# code.exe         pid: 67890  type: File  C:\path\to\file

# 該当プロセスを終了
taskkill /PID 12345 /F

GUI で確認するなら Process Explorer:

  1. Process Explorer をダウンロード
  2. Find → Find Handle or DLL (Ctrl + F)
  3. ファイル名を入力 → 該当プロセスが表示される
  4. 右クリック → Kill Process

対処3: Git で強制的に進める

# 未追跡ファイルとディレクトリを強制削除
git clean -fd

# .gitignore のファイルも含めて削除
git clean -fdx

# 確認だけ(dry run)
git clean -fdn

# checkout を強制
git checkout -f main

# stash で逃がす
git stash --include-untracked
git checkout main

対処4: パーミッション / 読み取り専用属性

# 読み取り専用属性を解除
attrib -R "C:\path\to\file" /S

# フォルダ全体を再帰的に
attrib -R "C:\path\to\folder\*" /S /D

# ACL リセット
icacls "C:\path\to\folder" /reset /T /C

対処5: アンチウイルスの除外設定

大量ファイルの削除はアンチウイルスのリアルタイムスキャンと競合します。開発フォルダを除外すると劇的に改善します:

  1. Windows セキュリティ → ウイルスと脅威の防止 → 設定の管理 → 除外
  2. 除外の追加 → フォルダー
  3. C:\Users\YourName\projects 等を追加
  4. node_modulesvendor 配下も対象に

対処6: WSL / Docker のロック

# WSL 内でファイルを開いているプロセスがある場合
wsl --shutdown

# Docker Desktop を停止
# タスクトレイから Quit Docker Desktop

# WSL 内から Windows ファイルにアクセス中なら停止
wsl -d Ubuntu --user root
fuser -k /mnt/c/path/to/file

頻出シナリオ別の対処

シナリオ典型的なロックプロセス対処
git pull で node_modulesnode.exe / esbuild.exe / vitedev サーバー停止
git checkout で vendorphp.exe (artisan serve) / php-fpmphp プロセス停止
git clean で .vs / .ideadevenv.exe / idea64.exeIDE 完全終了
OneDrive 同期フォルダOneDrive.exe同期一時停止 or 開発フォルダ除外
Defender スキャン中MsMpEng.exe除外フォルダ追加

予防策

  • 開発作業前に dev サーバー / IDE を必要なものだけ起動
  • node_modules / vendor はアンチウイルス除外に
  • 大規模 git checkout 前に npm stop / php artisan serve 停止
  • WSL2 backend の Docker は Linux ファイルシステム配下に置く(/home/user 等)
  • Sysinternals Suite を C:\tools\sysinternals 等に常備

FAQ

Q: y を押し続ければいつか進む?
A: ロックが解除されれば進みますが、原因解決の方が早いです。n を押すと操作キャンセル、その後手動で対処。

Q: 管理者権限で Git を実行すれば解決?
A: 場合によります。Windows のファイルロックは権限ではなくロックの仕組み。ロックを掛けているプロセスを終了するのが正解。

Q: WSL2 で git を使えば回避できる?
A: はい。WSL2 の Linux ファイルシステム(~/projects 等)に clone すれば Linux 流のセマンティクスで動作し、このエラーは出ません。Windows 側からは \\wsl$\Ubuntu\home\user でアクセス。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. fatal: remote origin already exists.
  2. fatal: '~' does not appear to be a git repository
  3. Cannot rebase: You have unstaged changes. Please commit or stash them.
  4. remote: error: denying non-fast-forward refs/heads/master (you should pull first)
  5. error: pathspec ... did not match any file(s) known to git.
  6. The following untracked working tree files would be overwritten by checkout
  7. fatal: Not a valid object name: 'master'.
  8. Unlink of file 'ファイル名' failed. Should I try again? (y/n)
  9. Another git process seems to be running in this repository, ~
  10. error: Your local changes to the following files would be overwritten by checkout: