Git を使い始めたばかりの人からよくされる質問に「Git でファイルの追跡をやめるようにするにはどうすればよいですか?」というものがあります。git rm コマンドを使うと Git リポジトリからファイルを削除できます。このコマンドは git add コマンドと逆の動きをするものだと捉えられます。

git rm の概要

git rm コマンドを使うと単一のファイルまたは複数のファイルを削除できます。git rm の基本的な機能は Git インデックスから追跡対象ファイルを削除することです。また、git rm を使ってステージング インデックスと作業ディレクトリの両方からファイルを削除できます。作業ディレクトリのみからファイルを削除する場合は、特にオプションはありません。コマンドで指定するファイルは現在の HEAD にあるファイルと一致している必要があります。HEAD にあるファイルとステージング インデックスまたは作業ツリーのファイルに差異がある場合、削除は実行されません。これは確定されていない変更が削除されるのを防止するための安全策です。

git rm ではブランチは削除されません。詳細については Git ブランチの使い方を参照してください。

使用法

<file>…​

削除するファイルを指定します。オプション値として、単一のファイル、file1 file2 file3 のようにスペースで区切られた複数のファイル、ワイルドカード ファイル グロブ (~./directory/*) を指定できます。

-f
--force

-f オプションは、Git で HEAD のファイルと、ステージング インデックスおよび作業ディレクトリの現在のコンテンツを一致させるセーフティ チェックを上書きするのに使います。

-n
--dry-run

「ドライ ラン」オプションでは git rm コマンドが実行されますが、 実際にファイルが削除されることはありません。このオプションでは実際に削除する代わりに削除対象となるファイルが出力されるので、 安心して削除を実行できます。

-r

-r オプションは「Recursive」の頭文字を取ったものです。 Recursive モードで git rm を実行すると、ターゲット ディレクトリとそのディレクトリのすべてのコンテンツが削除されます。

--

区切り文字のオプションを使うと、git rm に渡されるファイル名と引数のリストを明示的に区別できます。 ファイル名の一部がオプション名と混同してしまうような 文字列になっている場合に便利なオプションです。

--cached

cached オプションではステージングインデックスでのみ削除が行われるように指定できます。 作業ディレクトリのファイルは削除されません。

--ignore-unmatch

これによって、一致するファイルがない場合でもコマンドは「0 sigterm」ステータスで終了します。これは Unix で使われるステータス コードです。コード 0 は、コマンドが正常に呼び出されたことを意味します。より複雑なシェル スクリプトで適切なエラーを発生させるために git rm を使う場合には、--ignore-unmatch オプションが便利です。

-q
--quiet

quiet オプションでは、git rm コマンドの出力が表示されません。このコマンドでは通常、削除したファイルごとに 1 行ずつ出力されます。

git rm の取り消し

git rm を実行したからといって更新が永続的なものになるわけではありません。このコマンドは、ステージング インデックスと作業ディレクトリが更新されます。新しいコミットが作成されて変更がコミット履歴に追加されるまで、これらの変更は確定されません。つまり、ここでの変更は一般的な Git コマンドで「取り消す」ことができるのです。

git reset HEAD

reset では現在のステージング インデックスと作業ディレクトリを HEAD コミットに戻せます。これによって git rm の実行結果が取り消されます。

git checkout .

checkout も同じように、HEAD からファイルの最新バージョンを復元します。

git rm を実行すると削除を確定させる新しいコミットが作成されます。git reflog を使って git rm を実行する前の ref を見つけられます。詳細については git reflog の使い方を参照してください。

ディスカッション

コマンドでは正確なパス、ワイルドカード ファイル グロブ パターン、正確なディレクトリ名を <file> 引数として指定できます。コマンドを実行すると、Git リポジトリに現在コミットされているパスだけが削除されます。

ワイルドカード ファイル グロブはすべてのディレクトリを対象にするため、ワイルドカード グロブを使うときは注意が必要です。directory/*directory* という例を取ってみましょう。最初の例では directory/ 内にあるすべてのサブファイルが削除されます。2 番目の例では directory1directory2directory_whatever など「directory」を含むすべてのディレクトリが削除されるという思わぬ結果を生みます。

git rm の適用範囲

git rm では現在のブランチだけが操作対象になります。作業ディレクトリとステージング インデックスのツリーでのみ削除が実行されます。新しいコミットが作成されるまでリポジトリ履歴でのファイルの削除は確定しません。

rm ではなく git rm を使う理由

Git リポジトリは、追跡対象のファイルで通常のシェルである rm コマンドの実行を検知します。 この時、削除を反映するために作業ディレクトリが更新されます。ステージング インデックスには削除が反映されません。削除されたファイルのパスで再度 git add コマンドを実行してステージング インデックスに変更を追加する必要があります。git rm コマンドはステージング インデックスでショートカットの役割を果たします。 このコマンドによって作業ディレクトリとステージング インデックスに削除が反映されます。

git rm Documentation/\*.txt

この例ではワイルドカード ファイル グロブを使って、Documentation ディレクトリの子であるすべての *.txt ファイルとそのサブディレクトリを削除します。

この例ではアスタリスク (*) をスラッシュでエスケープしている点に注目してください。スラッシュを使うことでワイルドカードが拡張されるのを防いでいます。このワイルドカードはその後ファイルのパス名と Documentation/ ディレクトリのサブディレクトリを拡張します。

git rm -f git-*.sh

この例では強制オプションを使って git-*.sh のワイルドカードに一致するすべてのファイルを対象にしています。強制オプションでは作業ディレクトリとステージング インデックスの両方からターゲットファイルを明示的に削除します。

ファイルシステムに存在しないファイルを削除する方法

rm ではなく git rm を使う理由」で説明したとおり、git rm は標準シェル rmgit add を結合して作業ディレクトリからファイルを削除し、削除結果をステージング インデックスにプロモートするのに便利なコマンドです。標準のシェル rm コマンドだけを使って複数のファイルを削除すると、リポジトリの中が散らかってしまいます。

次のコミットの一環として明示的に削除したすべてのファイルを記録する場合は、次のコミットの準備として git commit -a を実行してすべての削除イベントをステージング インデックスに追加します。

ただし、シェル rm で削除したファイルを完全に削除する場合は、以下のコマンドを使用します。

git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

このコマンドでは作業ディレクトリから削除したファイルのリストを生成し、そのリストを git rm --cached にパイプしてステージング インデックスを更新します。

Git rm のまとめ

git rm は、作業ディレクトリとステージング インデックスという、Git の基本となる 2 つの内部状態管理ツリーを操作するコマンドです。git rm コマンドを使うと Git リポジトリからファイルが削除されます。デフォルトのシェルである rm コマンドと git add を組み合わせた効果を持っている便利な手段です。このコマンドでは最初にファイルシステムからターゲットを削除してから、その削除イベントがステージング インデックスに追加されます。Git での変更を元に戻す手段の 1 つでもあります。