Git:リポジトリからファイルを削除せずにインデックスからファイルを削除する方法


163

使うとき

git rm --cached myfile

ローカルファイルシステムからは削除されません。これが目的です。ただし、ファイルのバージョン管理とコミットを既に行っており、それを中央リポジトリにプッシュし、コマンドを使用する前に別のリポジトリにプルした場合は、そのシステムからファイルが削除されます。

ファイルシステムから削除せずに、バージョン管理からファイルを削除する方法はありますか?

編集:明確にしたいと思います。


おそらく、ユースケースを拡張することができます。インデックスは次のコミットのステージング領域なので、現在のブランチから削除したくないのに、なぜファイルをインデックスから削除したいのですか?
CBベイリー

1
申し訳ありません。私はmyfileが何らかの理由でコミットされ、かなり前に配布されたことを意味しました。現在の目標は、ユーザーのシステムから削除せずに、バージョニングから削除することです。これが発生した理由は、誤って設定ファイルをバージョンアップしたためです。設定ファイルは必要なので、外部システムから削除したくありません。
Fletcher Moore

質問をより明確にするために編集しました。
Fletcher Moore

3
git rm --cachedは、他の作業ディレクトリからファイルを削除しません。ファイルは、そのディレクトリで作業している誰かがプルを実行した場合にのみ削除されます。ファイルは「git checkout HEAD @ {1} foo」で簡単に復元できます(プルの直後に実行された場合)
William Pursell

回答:


119

私は、Gitコミットが「このファイルの追跡を停止するが、削除しない」などの意図を記録できるとは思わない。

このような意図を実現するには、ファイルを削除するコミットをマージ(またはリベース)するリポジトリーのGitの外部での介入が必要になります。


コピーの保存、削除の適用、復元

おそらく、最も簡単な方法は、ダウンストリームユーザーにファイルのコピーを保存し、削除をプルしてからファイルを復元するように指示することです。それらがリベースを介してプルしていて、ファイルに「変更」を行っている場合、競合が発生します。このような競合を解決するには、git rm foo.conf && git rebase --continue(競合するコミットに削除されたファイル以外の変更があるgit rebase --skip場合)または(競合するコミットが削除されたファイルにのみ変更された場合)を使用します。

ファイルを削除するコミットをプルした後、追跡されていないファイルを復元する

彼らがすでに削除コミットをプルしている場合でも、git showを使用して以前のバージョンのファイルを復元できます。

git show @{1}:foo.conf >foo.conf

または、git checkoutを使用します(William Pursellによるコメントごと。ただし、インデックスから削除してください)。

git checkout @{1} -- foo.conf && git rm --cached foo.conf

削除をプルした後(または、リベースでデタッチされたHEADにプルしている場合)に他のアクションを実行した場合は、以外のものが必要になる場合があります@{1}。彼らはgit log -gあなたが削除をプルする直前にコミットを見つけるために使うことができます。


コメントで、「追跡を解除しますが、保持したい」ファイルは、ソフトウェアを実行するために必要なある種の構成ファイルです(リポジトリから直接)。

ファイルを「デフォルト」として保持し、手動/自動でアクティブ化

リポジトリ内の構成ファイルのコンテンツを維持し続けることが完全に許容できない場合は、追跡されたファイルの名前を(たとえば)foo.confからに変更し、名前変更コミットを適用foo.conf.defaultしたcp foo.conf.default foo.conf後にユーザーに指示することができます。または、ユーザーがすでにリポジトリの既存の一部(たとえば、スクリプト(Makefileまたはリポジトリのコンテンツによって構成された他のプログラム)など)を使用してソフトウェアを起動/展開する場合、起動メカニズムにデフォルトのメカニズムを組み込むことができます。展開プロセス:

test -f foo.conf || test -f foo.conf.default &&
    cp foo.conf.default foo.conf

このようなデフォルトのメカニズムを使用すると、ユーザーは、追加の作業を行うことなく、名前foo.confを変更するコミットをプルできるはずfoo.conf.defaultです。また、将来追加のインストール/リポジトリを作成する場合、構成ファイルを手動でコピーする必要がなくなります。

いずれにしても、履歴の書き換えには手動による介入が必要です…

リポジトリのコンテンツを維持することが許容できない場合は、のようなものを使用して、履歴から完全に根絶する必要がありますgit filter-branch --index-filter …。これは履歴の書き換えに相当し、ブランチ/リポジトリごとに手動での介入が必要になります(git rebaseマンページの「アップストリームRebaseからの復旧」セクションを参照)。構成ファイルに必要な特別な処理は、書き換えから回復するときに実行する必要があるもう1つの手順です。

  1. 構成ファイルのコピーを保存します。
  2. 書き換えから回復します。
  3. 構成ファイルを復元します。

無視して再発を防ぐ

どの方法を使用する場合でも.gitignore、リポジトリのファイルに構成ファイル名を含めて、誰かがうっかり間違ってgit add foo.conf(これは可能ですが-f/ が必要になる--force)ことがないようにします。複数の構成ファイルがある場合は、それらをすべて1つのディレクトリに「移動」し、すべてを無視することを検討する場合があります(「移動」とは、プログラムが構成ファイルを検索する場所を変更し、ユーザー(または起動/展開メカニズム)を使用して、ファイルを新しい場所にコピー/移動します。無視するディレクトリにファイルをgit mvしたくないことは明らかです)。


5
信じられないほど徹底した対応。ありがとうございました!
Fletcher Moore、

以下のトムパワーの回答は、最初の文と矛盾しているようです。
Mike S

1
@MikeS:の影響--{,no-}assume-unchangedは純粋にローカルです。その状態はコミットに直接記録されません。これは、リポジトリがファイルに新しい変更をコミットするのを防ぐのに役立ちますが、バージョン管理からは削除されません。すべてのあなたの関連、関連、非裸のリポジトリのためにそれを設定することができれば、それはあなたの状況を助けるかもしれないが、あなたができることを何かではありません、直接(他の関連する、非裸のリポジトリに、特にもののことを+プル/リベースを押します質問に対する元の質問者の明確なコメントに従って、あなたは制御しません:「人のシステム」/「外国のシステム」を参照してください)。
Chris Johnsen、2014

1
I do not think a Git commit can record an intention like “stop tracking this file, but do not delete it”.-できるようになりましたgit rm --cached foo.conf
Nick Volynkin

1
@NickVolynkin:質問は、これが質問者の目的には不適切であることをすでに示していますか?結果のコミットが別のリポジトリにプルされたときに、(自動的に)ファイルを保持しますか?
Chris Johnsen

86

今週私が誤ってコミットしたときと同じ問題があり、共有リポジトリからビルドファイルを削除しようとしましたが、これは次のとおりです。

http://gitready.com/intermediate/2009/02/18/temporarily-ignoring-files.html

私にとってはうまくいき、今のところ言及していません。

git update-index --assume-unchanged <file>

必要なファイルをバージョン管理から削除するには、通常どおり他のすべてのコマンドを使用します。

git update-index --no-assume-unchanged <file>

元に戻したい場合。

編集:Chris JohnsenとKPMからのコメントを参照してください。これはローカルでのみ機能し、他のユーザーもファイルをバージョン管理しない限り、ファイルはバージョン管理されたままになります。受け入れられた答えはこれに対処するためのより完全な/正しい方法を提供します。また、この方法を使用する場合のリンクからのメモ:

明らかに、これに関係するかなりの数の警告があります。gitでファイルを直接追加すると、インデックスに追加されます。このフラグをオンにしてコミットをマージすると、マージが正常に失敗するため、手動で処理できます。


7
これは、言及された特定の問題に対する回答ではありません。それはあなた自身のローカルリポジトリでのみ機能するので、各ユーザーは自分でこれを行う必要があります。それは苦痛です。
KPM、2015

28

インデックスからファイルを削除するには、次を使用します。

git reset myfile

これはローカルコピーや他の人のコピーには影響しません。


1
resetファイルが現在のHEADコミットにない場合にのみ、インデックスからファイルを削除します。それ以外の場合は、インデックスバージョンを現在のHEADバージョンに戻します。
CBベイリー

1
質問を誤解しているかもしれませんが、それはコミットに影響を与えずにインデックスからファイルを削除することに関連しているようです。
Armand

Charlesが言ったように、リセットは「ファイルを削除」しません。詳細については、「git help reset」と入力してください。
Simon B.

4
これは、「リポジトリからファイルを削除せずにインデックスからファイルを削除する方法」というタイトルの質問に答えます。OPは「ローカルコピーを削除せずにファイルの追跡を解除するにはどうすればよいですか」と本当に尋ねていましたが。
ヒューソニズム2015

@hewsonism OPは「編集前」でも「任意のファイルシステム」と言っていました。
jbobbins


15

git rm --cachedコマンドを実行した後myfile.gitignoreファイルに追加してみてください(ファイルが存在しない場合は作成してください)。これはgitに無視するように伝えますmyfile

.gitignoreファイルはバージョン管理されているので、あなたはそれをコミットし、リモートリポジトリにプッシュする必要があります。


1

私の解決策は、他の作業コピーをプルしてから行うことです:

git log --pretty="format:" --name-only -n1 | xargs git checkout HEAD^1

最新のコメントですべてのファイルパスを取得し、HEADの親からチェックアウトすることを示しています。仕事が終わりました。


0

上記のソリューションは、ほとんどの場合問題なく機能します。ただし、そのファイルのすべてのトレース(つまり、パスワードなどの機密データ)も削除する必要がある場合は、ファイルをまだそこから取得できるため、コミット履歴全体からも削除する必要があります。

以下は、ファイルが存在しなかったかのように、コミット履歴全体からファイルのすべてのトレースを削除し、ファイルをシステムの適切な場所に保持するソリューションです。

https://help.github.com/articles/remove-sensitive-data/

ローカルのgitリポジトリを使用していて、予行演習を実行する必要がない場合は、実際にステップ3にスキップできます。私の場合、すでに.gitignoreファイルを作成していて、作業したいリポジトリにあったため、手順3と6だけが必要でした。

変更を確認するには、リポジトリのGitHubルートに移動してページを更新する必要がある場合があります。次に、リンクをナビゲートして、以前にファイルがあった古いコミットに移動し、ファイルが削除されたことを確認します。私にとって、古いコミットページを更新するだけでは変更は表示されませんでした。

最初は威圧的に見えましたが、本当に簡単で、魅力のように機能しました。:-)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.