web-dev-qa-db-ja.com

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

使用するとき

git rm --cached myfile

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

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

編集:明確化、願っています。

154
Fletcher Moore

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.conffoo.conf.defaultに名前変更するコミットをプルでき、余分な作業を行う必要がありません。また、将来追加のインストール/リポジトリを作成する場合、構成ファイルを手動でコピーする必要がなくなります。

とにかく履歴の書き換えには手動介入が必要です…

リポジトリ内のコンテンツを維持することが受け入れられない場合、おそらく git filter-branch --index-filter … のようなもので履歴から完全に根絶したいと思うでしょう。これは履歴の書き換えに相当し、各ブランチ/リポジトリの手動介入が必要になります( git rebaseマンページ )。構成ファイルに必要な特別な処理は、書き換えから回復するときに実行する必要がある別の手順にすぎません。

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

再発を防ぐために無視する

使用する方法が何であれ、リポジトリ内の.gitignoreファイルに構成ファイル名を含めて、だれも誤ってgit add foo.confを再度できないようにすることができます(可能ですが、-f/--forceが必要です)。複数の構成ファイルがある場合は、すべてを単一のディレクトリに「移動」し、全体を無視することを検討するかもしれません(「移動」とは、プログラムが構成ファイルを検索する場所を変更し、ユーザーを取得することを意味します(またはファイルを新しい場所にコピー/移動するための起動/展開メカニズム;明らかにgit mvファイルをディレクトリにあなたは無視されます)。

111
Chris Johnsen

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

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

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

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

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

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

あなたがそれを元に戻したいと思ったなら。

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

明らかに、これにはいくつかの注意事項があります。 gitファイルを直接追加すると、インデックスに追加されます。このフラグをオンにしてコミットをマージすると、マージが正常に失敗するため、手動で処理できます。

86
Tom Power

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

git reset myfile

これは、ローカルコピーまたは他のユーザーのコピーに影響を与えません。

30
Armand

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

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

15
awgy
  1. git rm --cached remove_file
  2. gitignoreにファイルを追加
  3. git add .gitignore
  4. git commit -m "Excluding"
  5. 楽しんで ;)

私の解決策は、他の作業コピーを引き出してから実行することです:

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

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

1
Tom Viner

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

これは、コミット履歴全体からファイルのすべてのトレースを削除するソリューションです。あたかも存在しないかのように、システム上のファイルを保持します。

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

ローカルgitリポジトリにいて、ドライランを実行する必要がない場合は、実際にステップ3にスキップできます。私の場合、既に.gitignoreファイルを作成しており、作業したいリポジトリにいたため、手順3と6のみが必要でした。

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

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

0
SherylHohman