Git で「error: untracked working tree files would be overwritten by checkout」を処理する方法

GitBeginner
オンラインで実践に進む

はじめに

Git は、現代のソフトウェア開発に不可欠な強力なバージョン管理システムです。Git を使用していると、「error: untracked working tree files would be overwritten by checkout」というエラーメッセージに遭遇することがあります。このエラーは、ブランチを切り替えようとした際に、Git がその操作によって、現在の作業ディレクトリ内の Git でまだ追跡されていないファイルが上書きされることを検出した場合に発生します。これは、意図しないデータ損失を防ぐための安全機能です。

この実験では、この一般的なエラーの原因、競合するファイルを特定する方法、およびそれを解決するためのいくつかの方法を学びます。このチュートリアルを終える頃には、Git ワークフローをより効果的に管理し、このエラーに自信を持って対処できるようになるでしょう。

チェックアウトエラーの再現

エラーの修正方法を理解するために、まずエラーを再現してみましょう。これにより、Git が競合を報告する理由が明確になります。セットアップスクリプトはすでに 2 つのブランチ(mainfeature-branch)を持つ Git リポジトリを作成しています。feature-branchには、mainブランチでローカルに作成するファイルが含まれています。

まず、プロジェクトディレクトリに移動します。この実験のすべてのコマンドはこのディレクトリから実行されます。

cd ~/project/git-checkout-demo

リポジトリの現在の状態を確認し、すべてがクリーンであることを確認しましょう。

git status

出力は次のようになります。

On branch main
nothing to commit, working tree clean

これにより、保留中の変更がないmainブランチにいることが確認できます。次に、利用可能なブランチをリスト表示しましょう。

git branch

2 つのブランチが表示され、*が現在のブランチを示します。

  feature-branch
* main

次に、競合を作成しましょう。現在の作業ディレクトリにfeature.mdという名前の新しいファイルを作成します。このファイルは現在、mainブランチでは Git によって「追跡されていません」が、feature-branchでは同じ名前のファイルがすでに存在し、追跡されています。

echo "## My local changes to feature documentation" > feature.md

新しい追跡されていないファイルを確認するために、再度ステータスを確認しましょう。

git status

出力には、feature.mdが追跡されていないファイルとして表示されます。

On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	feature.md

nothing added to commit but untracked files present (use "git add" to track)

最後に、feature-branchに切り替えようとします。

git checkout feature-branch

このコマンドは失敗し、調査中のエラーが発生します。

error: The following untracked working tree files would be overwritten by checkout:
	feature.md
Please move or remove them before you switch branches.
Aborting

Git は、feature-branchからのバージョンによってローカルの追跡されていないfeature.mdファイルが上書きされるのを保護するために、チェックアウトを中止しました。次のステップでは、この問題を解決するためのさまざまな方法を検討します。

git stash による競合の解決

このエラーを解決するための最も安全で一般的な方法の 1 つは、git stashを使用することです。このコマンドは、ローカルの変更(ステージングされたものとステージングされていないものの両方)を一時的に保存し、作業ディレクトリを最後のコミットに一致するようにリセットします。これにより、自由にブランチを切り替えることができます。

現在、追跡されていないfeature.mdファイルが競合を引き起こしているmainブランチにいます。

追跡されていないファイルをスタッシュするには、--include-untracked(または-u)オプションを使用する必要があります。

git stash push --include-untracked

確認メッセージが表示されます。

Saved working directory and index state WIP on main: <commit_hash> Initial commit with README

ここで、リポジトリのステータスを再度確認します。

git status

作業ツリーはクリーンになり、追跡されていないファイルはなくなりました。

On branch main
nothing to commit, working tree clean

作業ディレクトリがクリーンになったので、エラーなしでfeature-branchに切り替えることができます。

git checkout feature-branch

コマンドは成功します。

Switched to branch 'feature-branch'

これでfeature-branchにいます。feature.mdを確認すると、このブランチに属するバージョンが表示されます。

cat feature.md
## Official Feature Documentation

ローカルの変更はスタッシュに安全に保存されています。それらを取り戻すには、mainブランチに戻ってスタッシュを適用します。

git checkout main
git stash pop

git stash popコマンドは、スタッシュされた変更を再適用し、スタッシュリストから削除します。feature.mdファイルが作業ディレクトリに戻りました。

次のステップのために、競合状態に戻っていることを確認しましょう。git stash popコマンドを実行した場合、すでにその状態になっています。

git clean による競合の解決

競合を解決する別の方法は、追跡されていないファイルを削除することです。この方法は、追跡されていないファイルが不要であることを確信している場合にのみ適しています。この目的にはgit cleanコマンドが使用されます。

警告: このコマンドはファイルを永久に削除するため、注意して使用してください。

まず、追跡されていないfeature.mdファイルがあるmainブランチで競合状態にあることを確認しましょう。

cd ~/project/git-checkout-demo
git checkout main
## feature.mdが存在しない場合は、再作成します
if [ ! -f "feature.md" ]; then echo "## My local changes" > feature.md; fi
git status

何かを削除する前に、-nフラグを使用して「ドライラン」を実行するのがベストプラクティスです。これにより、実際にファイルを削除せずに、どのファイルが削除されるかを確認できます。

git clean -n

出力には削除されるファイルがリストされます。

Would remove feature.md

これらのファイルを削除することを確認したら、-f(force)フラグを付けてコマンドを再度実行できます。

git clean -f

Git は削除を確認します。

Removing feature.md

追跡されていないファイルがなくなったので、作業ディレクトリはクリーンになり、問題なくブランチを切り替えることができます。

git checkout feature-branch

チェックアウトは成功します。

Switched to branch 'feature-branch'

この方法は高速ですが破壊的です。前のステップのgit stash方法は、作業を保持するため、一般的に安全です。

ファイルの追跡とベストプラクティスによる解決

場合によっては、追跡されていないファイルは破棄するものではなく、保持したい作業であることがあります。この場合、正しいアプローチは、ファイルをコミットして Git の追跡システムに追加することです。このセクションでは、そもそもこのエラーが発生しないようにするためのベストプラクティスについても説明します。

まず、mainブランチに戻り、競合するファイルを再作成しましょう。

cd ~/project/git-checkout-demo
git checkout main
echo "## My local changes to feature documentation" > feature.md

方法:ファイルの追跡

追跡されていないファイルが重要である場合は、現在のブランチにコミットする必要があります。

  1. ファイルをステージングエリアに追加します。

    git add feature.md
  2. ステージングされたファイルをコミットします。

    git commit -m "Add local version of feature.md"

変更がmainブランチに安全にコミットされたので、Git は切り替えを処理できます。feature-branchをチェックアウトすると、Git は単にワークスペースファイルをそのブランチのバージョンで置き換えます。

git checkout feature-branch

チェックアウトは成功します。コミットされた変更はmainブランチの履歴に安全に保存されています。

ベストプラクティス:.gitignoreの使用

特定のファイル(ログ、ビルド成果物、環境ファイルなど)が追跡されないようにするには、.gitignoreファイルを使用する必要があります。Git は、.gitignore内のパターンに一致するファイルまたはディレクトリを無視し、それらが競合する追跡されていないファイルになるのを防ぎます。

すべての.logファイルを無視するために.gitignoreファイルを作成しましょう。

## .gitignoreファイルを追加するためにmainに戻ります
git checkout main

## .gitignoreファイルを作成します
echo "*.log" > .gitignore

次に、ログファイルを作成します。

touch app.log

ステータスを確認します。

git status

app.logが追跡されていないファイルとして表示されないことに注意してください。ただし、.gitignoreファイル自体は追跡されていません。

On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	.gitignore

nothing added to commit but untracked files present (use "git add" to track)

ルールがプロジェクト全体で共有されるように、常に.gitignoreファイルをコミットする必要があります。

git add .gitignore
git commit -m "Add .gitignore to ignore log files"

頻繁にコミットし、.gitignoreを効果的に使用することで、このチェックアウトエラーに遭遇する可能性を大幅に減らすことができます。

まとめ

この実験では、Git で「error: untracked working tree files would be overwritten by checkout」というエラーを診断し、解決する方法を学びました。

以下のことを達成しました。

  1. エラーの再現: エラーをトリガーするシナリオを正常に作成し、その原因を明確に理解しました。
  2. git stash による解決: git stash を使用して追跡されていないファイルを一時的に保存し、作業を失うことなく安全にブランチを切り替える方法を学びました。
  3. git clean による解決: 不要になった追跡されていないファイルを削除するために git clean を使用する方法を学びました。その際、間違いを避けるためにまずドライランを実行しました。
  4. ファイルの追跡による解決: 保持したい作業である追跡されていないファイルをコミットすることで問題を解決する方法を学びました。
  5. ベストプラクティスの学習: 一時ファイルやビルド関連のファイルが競合を引き起こすのを防ぐために .gitignore ファイルを使用する方法を学びました。

これらのテクニックを習得することで、よりクリーンで効率的な Git ワークフローを維持し、開発者が直面する最も一般的な問題の 1 つに自信を持って対処できるようになります。