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 の使い方のページを参照してください。

ディスカッション

コマンドでは正確なパス、ワイルドカードファイルグロブパターン、正確なディレクトリ名を 引数として指定できます。コマンドを実行すると、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 つでもあります。