「untracked working tree files would be overwritten by checkout」は、現在の未追跡ファイルと、切り替え先で追跡される同じパスが衝突する警告です。Gitは上書きを避けて処理を止めています。強制切り替えや削除ではなく、確認、外部保管、切り替え、元ブランチでの復元確認の順に進めます。
対象は通常の単一リポジトリです。submodule、別worktree、ファイル名の大小文字だけが違う衝突などは別途診断してください。
1. 警告パスとignoredを確認する
エラーに列挙されたパスを控え、元ブランチ名も記録します。次はPowerShellでの確認例です。
git branch --show-current
git status --short --untracked-files=all
git status --short --ignored??は未追跡、!!はignoredの目安です。次の架空パスは、実際の警告パスへ置き換えます。
git check-ignore -v -- 'notes/report.txt'ignoredファイルは通常の状態表示に出にくく、通常のブランチ切り替えでは黙って上書きされることがあります。Git公式のcheckout資料は、防止用の --no-overwrite-ignore を案内しています。重要なignoredも外部保管してください。
2. 元ファイルを残したまま外部コピーを作る
まず警告対象をリポジトリ外へコピーし、保管先と元ファイルの内容を照合します。次は秘密情報を含まない架空の notes/report.txt 1個を扱うPowerShell例です。パスと切り替え先の名前を自分の状況に合わせ、同じPowerShellセッションで順に進めます。現在の元ブランチ名は自動で控えます。
新しい一意の保管フォルダーを作り、既存ファイルの上書きを避けます。表示される保管先を控え、ファイルを開いて内容も確かめてください。コピーしただけでは警告の原因となる元ファイルは残っています。
$TargetPath = 'notes/report.txt'
$OriginalBranch = (git branch --show-current).Trim()
$RepositoryRoot = (git rev-parse --show-toplevel).Trim()
if ($LASTEXITCODE -ne 0 -or -not $OriginalBranch) { throw 'Check repository and branch first' }
$BackupDir = Join-Path ([IO.Path]::GetTempPath()) ('git-safety-' + [guid]::NewGuid().ToString('N'))
$RepoPrefix = [IO.Path]::GetFullPath($RepositoryRoot).TrimEnd('\', '/') + [IO.Path]::DirectorySeparatorChar
if ([IO.Path]::GetFullPath($BackupDir).StartsWith($RepoPrefix, [StringComparison]::OrdinalIgnoreCase)) {
throw 'Choose a backup location outside this repository'
}
New-Item -ItemType Directory -Path $BackupDir -ErrorAction Stop | Out-Null
$BackupFile = Join-Path $BackupDir 'report.txt'
if (Test-Path -LiteralPath $BackupFile) { throw 'Backup destination already exists' }
Copy-Item -LiteralPath $TargetPath -Destination $BackupFile -ErrorAction Stop
$OriginalHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $TargetPath).Hash
if ((Get-FileHash -Algorithm SHA256 -LiteralPath $BackupFile).Hash -ne $OriginalHash) {
throw 'Backup content does not match'
}
$BackupDir複数の警告パスはそれぞれ別の保管先へコピーして照合してください。秘密鍵、環境変数、個人情報などを含む場合やignoredの場合は、次のstash経路を使わず、後述の外部移動経路へ進みます。外部保管先のアクセス権と保存場所も自分の用途に合わせて選んでください。
3. 未追跡ファイルをstashへ退避する
主経路では、コピー後も元ファイルを作業ツリーに残したまま、stash push -uで退避します。先に元ファイルを移動すると、そのファイルはstashに入らず、あとでapplyしても戻りません。
Git公式のstash資料では、-uは未追跡を含め、ignoredは含めません。追跡中・ステージ済みの変更も退避するので、最初の状態表示とstash概要を照合します。-aならignoredも含みますが、この記事では自動的に範囲を広げません。
git stash push -u -m "before branch switch"
if ($LASTEXITCODE -ne 0) { throw 'Stash failed; stop here' }
git stash list
git stash show --include-untracked --stat "stash@{0}"
if ($LASTEXITCODE -ne 0) { throw 'Inspect saved stash before switching' }stash概要に対象があることを確認してください。対象ファイルが残る、何も保存されない、エラーが出る場合は切り替えずに確認します。stashはリポジトリ内部のデータであり、外部コピーの代わりにはしません。
4. 切り替え先では復元せず、元ブランチでapplyする
退避後、ignoredの上書きも防ぐオプションを付けて切り替えます。次のブランチ名は架空例です。
$DestinationBranch = 'feature/report'
git checkout --no-overwrite-ignore $DestinationBranch
if ($LASTEXITCODE -ne 0) { throw 'Switch failed; inspect the reported paths' }切り替え先には同名の追跡済みファイルがあります。そこでstashを適用すると、未追跡ファイルを同じパスへ戻せず失敗し得ます。復元するときは、先に控えた元ブランチへ戻ってからapplyします。
git checkout --no-overwrite-ignore $OriginalBranch
if ($LASTEXITCODE -ne 0) { throw 'Cannot return to original branch' }
git stash apply "stash@{0}"
if ($LASTEXITCODE -ne 0) { throw 'Restore failed; keep stash and backup for inspection' }PowerShellでは stash@{0} を二重引用符で囲みます。applyは成功時もstash項目を残します。競合や復元失敗が出たら、その項目と外部コピーを残し、強制削除せず状態を確認します。
5. 復元した内容を照合してからstashを消す
元の未追跡ファイル、退避した追跡変更、ステージ状態を最初の記録と比べます。通常のapplyはステージ状態を元どおりに戻すとは限らないため、内容が戻ったこととステージされていることを区別して確認してください。
git status --short --untracked-files=all
git stash list
git stash show --include-untracked --stat "stash@{0}"
if ((Get-FileHash -Algorithm SHA256 -LiteralPath $TargetPath).Hash -ne $OriginalHash) {
throw 'Restored file does not match the original'
}
if ((Get-FileHash -Algorithm SHA256 -LiteralPath $BackupFile).Hash -ne $OriginalHash) {
throw 'Backup content changed'
}ハッシュだけでなく、実ファイルを開いて内容を確認します。必要な変更がすべて戻り、外部コピーも読めると確かめた後だけ、この作業で作ったstash項目を削除します。途中で別のstashを作った場合は番号を再確認してください。
git stash drop "stash@{0}"popは適用成功時に項目を取り除くため、検証前には使いません。
別経路:ignoredや秘密データは外部へ移動して戻す
ignoredは-uで保存されません。秘密データもstashに入れず外部で扱います。この経路ではstashを使わず、手順2でコピーと照合を済ませた対象だけを作業ツリー外へ移動します。主経路のstash操作と続けて実行しないでください。
同じPowerShellセッションで、手順2の変数と確認済みコピーを引き継ぎます。$DestinationBranchには切り替えたい実際のブランチ名を設定してから実行します。追跡中の変更が切り替えを妨げる場合は、この経路だけでは解決しないため、その変更を別に確認します。
$DestinationBranch = 'feature/report'
$MovedFile = Join-Path $BackupDir 'report.txt.from-worktree'
if (Test-Path -LiteralPath $MovedFile) { throw 'Move destination already exists' }
Move-Item -LiteralPath $TargetPath -Destination $MovedFile -ErrorAction Stop
if ((Get-FileHash -Algorithm SHA256 -LiteralPath $MovedFile).Hash -ne $OriginalHash) {
throw 'Moved file does not match the original'
}
git checkout --no-overwrite-ignore $DestinationBranch
if ($LASTEXITCODE -ne 0) { throw 'Switch failed; keep the external files' }用事を終えたら元ブランチへ戻り、復元先が存在しないことを確認してからコピーを戻します。復元先に何かある場合は上書きせず止まり、両方を比較します。移動先とバックアップコピーは確認が済むまで残します。
git checkout --no-overwrite-ignore $OriginalBranch
if ($LASTEXITCODE -ne 0) { throw 'Cannot return to original branch' }
if (Test-Path -LiteralPath $TargetPath) { throw 'Restore destination already exists; inspect it first' }
$RestoreParent = Split-Path -Parent $TargetPath
if (-not (Test-Path -LiteralPath $RestoreParent -PathType Container)) {
New-Item -ItemType Directory -Path $RestoreParent -ErrorAction Stop | Out-Null
}
Copy-Item -LiteralPath $BackupFile -Destination $TargetPath -ErrorAction Stop
if ((Get-FileHash -Algorithm SHA256 -LiteralPath $TargetPath).Hash -ne $OriginalHash) {
throw 'Restored file does not match the backup'
}cleanやforceを最初に使わない
Git公式のclean資料では、-nは削除候補の表示だけを行い、-xを加えるとignoredも候補に含めます。
git clean -n -d
git clean -n -d -xcleanの削除実行やcheckoutの強制切り替えはファイルを失う可能性があります。保管と照合が済む前の直し方にしないでください。大切なのは、警告を消すだけでなく、元データを別の場所でも確認できる状態にしてから切り替えることです。
同じブランチが別の作業場所で使用中という警告なら、Gitのalready used by worktreeの対処手順で原因を分けて確認してください。


コメント