Windows で Git の worktree を削除しようとしたところ、遭遇したエラーの話です。
いつも通り git worktree remove --force を実行したのですが、.git/worktrees/... の削除で Permission denied になります。
最初は、
OneDrive 配下だから何か引っかかった?
と思いました。
.git の中は Git 自身が管理している場所なので、何も考えずフォルダを手動で消すのもちょっと怖かったため、細かく状況を確認しながら対応しました。
下記の通り、実際に確認した順番にまとめます。
- 実際に出たエラー
- なぜすぐ
.gitの中を削除しなかったのか - Git がその worktree をまだ管理しているか確認した方法
- Git 管理外だと確認してから残骸だけ削除した手順
- OneDrive や ReparsePoint との関係
- その場だけ直す場合の手順
- 最終的にリポジトリ自体を OneDrive 配下から外した理由
git worktree remove で Permission denied になった
今回削除しようとしたのは、一時的に作っていた worktree です。
PowerShell で次を実行しました。
git worktree remove --force "$env:TEMP\<ワークツリー名>"
すると、
Deletion of directory '.git/worktrees/<ワークツリー名>/logs' failed. Should I try again? (y/n)
と表示され、n を選びました。
この y / n は、「削除を強制するかどうか」ではなく、失敗したディレクトリ削除をもう一度試すかどうかです。
y を選べば Git が同じ削除処理を再試行します。たとえば一時的なファイルロックが原因で、その間にロックが外れれば削除できる可能性もあります。
ただ、今回はすでに一度削除に失敗しており、何が残っているのかも分からない状態でした。
そのため、何度も再試行するより、
いったん止めて、Git がその worktree をまだ管理対象として認識しているのか確認したい
という意図でした。
その後、
error: failed to delete '.git/worktrees/<ワークツリー名>': Permission denied
となりました。
TEMP 側の worktree を消したいだけなのに、削除できないのは .git/worktrees/... 側です。
ここで、
じゃあ残っている
.git/worktrees/...を手動で消す
ことも考えましたがそれはやめました。
.git 内を手動削除しなかった理由
.git/worktrees/... にフォルダが残っているからといって、それが単なる残骸なのか、Git がまだ管理対象として使っているものなのかは見た目だけでは分かりません。
なので、まず Git 自身が現在どの worktree を管理しているのかを下記コマンドで確認しました。
git worktree list --porcelain
結果は下記のみです。
worktree C:/Users/<ユーザー名>/OneDrive/Desktop/<プロジェクト名>
HEAD <HEAD のハッシュ>
branch refs/heads/main
削除しようとしていた、
<ワークツリー名>
は一覧にありません。
ここまで確認して、
- TEMP 側の worktree 実体はすでに消えている
- Git もその worktree を管理対象として認識していない
.git/worktrees/<ワークツリー名>だけが残っている
という状態だと判断しました。
つまり、ここで初めて、
Git がまだ使っている worktree ではなく、削除処理で残ったものだけが残ってるだけっぽい
と判断し、手動削除を進めました。
ReadOnly 属性を解除した
残っているディレクトリの属性が削除を邪魔している可能性を考え、手動削除する前に ReadOnly 属性を外しました。
attrib -R ".git\worktrees\<ワークツリー名>>\*" /S /D
結果は何も表示されず、そのまま正常終了しました。
ここでも、属性を外したからそのまま何でも削除するのではなく、前の手順で Git の管理対象から外れていることを確認済みというのが前提です。
Git 管理外だと確認した残骸だけ削除
ここまでで、対象の worktree はすでに Git の管理対象から外れていることを確認しています。
そのうえで、残っていた .git/worktrees/<ワークツリー名> だけを手動削除しました。
Remove-Item -LiteralPath ".git\worktrees\<ワークツリー名>" -Recurse -Force
今回はエラーなく無事削除成功しました。
Test-Path で本当に消えたか確認
削除コマンドがエラーにならなかった、ということだけで終わらせずに、本当に消えたかも確認しました。
Test-Path ".git\worktrees\<ワークツリー名>"
結果は、
False
でした。
これで .git/worktrees/... に残っていたディレクトリも削除できたことを確認できました。
OneDrive が直接の原因だったのか
今回の Git リポジトリは、次の場所にありました。
C:\Users\<ユーザー名>\OneDrive\Desktop\<プロジェクト名>
つまり、リポジトリ全体が OneDrive の同期対象です。
調査する中で、.git/worktrees/... 内の一部には、
ReparsePoint
属性があることも確認しました。
Windows の OneDrive Files On-Demand では、同期対象のファイルやフォルダに reparse point が使われることがあります。
今回実際に確認できたのは、
- Git リポジトリ全体が OneDrive 配下にあった
.git/worktrees/...の削除時に Permission denied になった- 対象には ReparsePoint 属性があった
- ReadOnly 属性を解除したあと、Git 管理外の残骸は手動削除できた
というところまでです。
なので、
OneDrive が100%直接の原因だった
とまでは言えません。
OneDrive Files On-Demand や同期処理、Windows の reparse point、ファイル属性、何らかのロックなどが絡み、.git 内部の削除処理と干渉した可能性が高いのかなと考えています。
また、Git 公式が「OneDrive 配下に Git リポジトリを置くことを非推奨としている」というような内容も確認していませんし。
今回の記事は、あくまで私の環境で実際に起きた症状と、そのときに行った対処の記録です。
その場では直ったけど、リポジトリ自体を OneDrive 配下から外すことにした
残骸を削除できたのでその場だけの問題は解決しましたが、以前にも何度か同じことが起こっていました。
Git の .git 内部には、
- refs
- logs
- worktree metadata
- lock
- 一時ファイル
など、更新・作成・削除されるものがいろいろあります。
今回の症状を見て、開発中の Git リポジトリを OneDrive の同期対象にしておくよりも、同期やファイル属性と干渉する可能性を避けることの方がメリットがでかいと判断しました。
そこで、
C:\Users\<ユーザー名>\OneDrive\Desktop\<プロジェクト名>
から、
C:\dev\<プロジェクト名>
へリポジトリを移しました。
もちろん、
OneDrive 配下なら Git が必ず壊れる
という話ではありませんが、複数回同じ事象になり、めんどくさいので OneDrive 配下から外しました。
実際に行った、リポジトリの安全な移行手順
移行の方法として、旧フォルダを Explorer でそのまま切り取り・貼り付けしたわけではありません。
GitHub を基準に新しい場所へ fresh clone し、.env.local やローカル専用ファイルだけは確認しながら移しました。
その途中では、
- 旧 repo の working tree が clean か
- 新旧の HEAD が一致しているか
npm ciと build が成功するか- fresh clone では引き継がれない
.git/info/exclude - build で発生した tracked file の差分
- 最後に
git status --shortが clean か
まで順番に確認しています。
実際に行った移行手順もまとめ中です。
まとめ
今回は git worktree remove --force を実行したところ、.git/worktrees/... の削除で Permission denied になりましたが、いきなり手動削除はしていません。
まず、
git worktree list --porcelain
で Git 自身がその worktree をまだ管理しているか確認しました。
対象が一覧から消えていることを確認してから、ReadOnly 属性を解除し、残骸だけ削除しました。
最後に、
Test-Path
で本当に消えたことまで確認しました。
OneDrive が直接の原因だったと断定はできませんが、今回の環境では OneDrive 配下の .git/worktrees/... で同じような事象が複数回起きています。
そのため、今回はその場しのぎの対処で終わらせず、開発リポジトリ自体を OneDrive 配下から外すことにしました。
同じように Permission denied が出た場合、まず Git が現在どう認識しているのかを確認してから操作するのがよさそうです。