(filename.orig
マージの解決中に)不要なファイルを数回前に自分のリポジトリに誤ってコミットしましたが、今まで気付かなかった。リポジトリの履歴からファイルを完全に削除したい。
filename.orig
そもそもリポジトリに追加されなかった変更履歴を書き換えることはできますか?
(filename.orig
マージの解決中に)不要なファイルを数回前に自分のリポジトリに誤ってコミットしましたが、今まで気付かなかった。リポジトリの履歴からファイルを完全に削除したい。
filename.orig
そもそもリポジトリに追加されなかった変更履歴を書き換えることはできますか?
回答:
質問に記載されている状況と異なる場合は、このレシピを使用しないでください。このレシピは、不適切なマージを修正し、修正をマージに反映します。
けれどもfilter-branch
、あなたがやりたいだろう、それは非常に複雑なコマンドであると私はおそらくでこれを行うことを選択しますgit rebase
。それはおそらく個人的な好みです。ソリューションはfilter-branch
単一の少し複雑なコマンドでrebase
実行できますが、ソリューションは同等の論理演算を一度に1ステップずつ実行します。
次のレシピを試してください。
# create and check out a temporary branch at the location of the bad merge
git checkout -b tmpfix <sha1-of-merge>
# remove the incorrectly added file
git rm somefile.orig
# commit the amended merge
git commit --amend
# go back to the master branch
git checkout master
# replant the master branch onto the corrected merge
git rebase tmpfix
# delete the temporary branch
git branch -d tmpfix
(実際には一時的なブランチは必要ありません。「デタッチされたHEAD」を使用してこれを行うことができますが、一時的なブランチを使用するのではなく、git commit --amend
ステップに生成されたコミットIDをメモしてgit rebase
コマンドに提供する必要があります。名前。)
git rebase -i
速く、まだ使いやすいようになりますか?$ git rebase -i <sh1-of-merge>正しいものを「編集」としてマークします$ git rm somefile.orig $ git commit --amend $ git rebase --continueしかし、何らかの理由で、まだ最後のどこかにそのファイルがあります私がやった時。おそらく何かが欠けています。
git rebase -i
特に、実行するrebase-y操作が複数ある場合は非常に便利ですが、実際に誰かの肩をポイントしていないときに、エディターで何をしているのかを確認できる場合を正確に説明するのは大変なことです。私はvimを使用していますが、「ggjcesquash <Esc> jddjp:wq」や「現在の2行目以降に最上行を移動し、4行目の最初の単語を「編集」に変更して、今すぐ保存して、終了」は実際の手順よりもすぐに複雑に見えます。通常、いくつかの--amend
and --continue
アクションも発生します。
元のポスターは次のように述べています:
不要なファイルを誤ってリポジトリにコミットしました...数回前にコミットしました...リポジトリの履歴からファイルを完全に削除したいと思います。
filename.orig
そもそもリポジトリに追加されなかった変更履歴を書き換えることはできますか?
gitからファイルの履歴を完全に削除するには、さまざまな方法があります。
オリジナルのポスターの場合、彼は後でいくつかの追加のコミットを行ったので、コミットを修正すること自体は実際にはオプションではありませんが、完全を期すために、必要な人のために、それを行う方法についても説明します以前のコミットを修正します。
これらのソリューションはすべて、何らかの方法で履歴/コミットを変更/再書き込みする必要があるため、コミットの古いコピーを持っている人は、新しい履歴と履歴を再同期するために追加の作業を行う必要があります。
以前のコミットで誤って変更(ファイルの追加など)を行い、その変更の履歴を残したくない場合は、以前のコミットを修正してファイルを削除するだけです。
git rm <file>
git commit --amend --no-edit
ソリューション#1と同様に、以前のコミットを削除したいだけの場合は、親をハードリセットするだけのオプションもあります。
git reset --hard HEAD^
このコマンドは、ブランチを前の最初の親コミットにハードリセットします。
しかしながら、元のポスターのように、変更を元に戻すコミットの後にいくつかのコミットを行った場合でも、ハードリセットを使用して変更を加えることができますが、これにはリベースの使用も含まれます。履歴をさらに遡ってコミットを修正するために使用できる手順は次のとおりです。
# Create a new branch at the commit you want to amend
git checkout -b temp <commit>
# Amend the commit
git rm <file>
git commit --amend --no-edit
# Rebase your previous branch onto this new commit, starting from the old-commit
git rebase --preserve-merges --onto temp <old-commit> master
# Verify your changes
git diff master@{1}
これは、履歴からコミットを完全に削除したい場合にのみ機能します。
# Create a new branch at the parent-commit of the commit that you want to remove
git branch temp <parent-commit>
# Rebase onto the parent-commit, starting from the commit-to-remove
git rebase --preserve-merges --onto temp <commit-to-remove> master
# Or use `-p` insteda of the longer `--preserve-merges`
git rebase -p --onto temp <commit-to-remove> master
# Verify your changes
git diff master@{1}
このソリューションを使用すると、ソリューション#2および#3と同じことを実行できます。つまり、直前のコミットよりも履歴の中でコミットを変更または削除するため、どのソリューションを使用するかはユーザー次第です。インタラクティブなリベースは、パフォーマンス上の理由から、数百のコミットのリベースにはあまり適していないため、このような状況では、非インタラクティブなリベースまたはフィルターブランチソリューション(下記参照)を使用します。
インタラクティブリベースを開始するには、以下を使用します。
git rebase --interactive <commit-to-amend-or-remove>~
# Or `-i` instead of the longer `--interactive`
git rebase -i <commit-to-amend-or-remove>~
これにより、gitはコミット履歴を、変更または削除するコミットの親に巻き戻します。次に、gitが使用するように設定されているエディタ(デフォルトではVim)で巻き戻しコミットのリストを逆の順序で表示します。
pick 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
pick 7668f34 Modify Bash config to use Homebrew recommended PATH
pick 475593a Add global .gitignore file for OS X
pick 1b7f496 Add alias for Dr Java to Bash config (OS X)
変更または削除するコミットは、このリストの一番上に表示されます。削除するには、リストからその行を削除します。それ以外の場合は、次のように、1行目の「pick」を「edit」に置き換えます。
edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
次に、と入力しgit rebase --continue
ます。コミットを完全に削除することを選択した場合は、実行する必要があるのはそれだけです(検証以外の場合は、このソリューションの最終ステップを参照してください)。一方、コミットを変更したい場合、gitはコミットを再適用し、リベースを一時停止します。
Stopped at 00ddaacab0a85d9989217dd9fe9e1b317ed069ac... Add symlinks
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
この時点で、ファイルを削除してコミットを修正してから、リベースを続行できます。
git rm <file>
git commit --amend --no-edit
git rebase --continue
それでおしまい。最後のステップとして、コミットを変更したか完全に削除したかに関係なく、リベース前の状態と比較して、ブランチに他の予期しない変更が加えられていないことを常に確認することをお勧めします。
git diff master@{1}
最後に、この解決策は、ファイルの存在のすべての痕跡を履歴から完全に一掃したい場合に最適です。他の解決策はどれもタスクに完全には対応していません。
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>'
<file>
ルートコミットから始めて、すべてのコミットから削除されます。代わりにコミット範囲を書き換えたいだけの場合は、この回答で指摘されて
HEAD~5..HEAD
いるように、追加の引数としてに渡すことができます。filter-branch
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD
この場合も、filter-branch
が完了した後は、通常、ブランチをフィルタリング操作前の以前の状態と比較して、予期しない変更が他にないことを確認することをお勧めします。
git diff master@{1}
BFG Repo Cleanerツールはよりも高速に実行されると聞きました。そのgit filter-branch
ため、オプションとして確認することもできます。フィルターブランチのドキュメントでは、実行可能な代替策として公式に言及されています。
git-filter-branchを使用すると、Gitの履歴をシェルスクリプトで複雑に書き換えることができますが、大きなファイルやパスワードなどの不要なデータを単に削除する場合は、この柔軟性は必要ありません。これらの操作については、git-filter-branchに代わるJVMベースのBFG Repo-Cleanerを検討することをお勧めします。これらのユースケースでは通常、少なくとも10倍から50倍高速で、まったく異なる特性があります。
ファイルの特定のバージョンは1回だけクリーンアップされます。BFGは、git-filter-branchとは異なり、履歴内のどこでまたはいつコミットされたかに基づいてファイルを異なる方法で処理する機会を提供しません。この制約は、BFGのコアパフォーマンス上の利点を与え、不良データをクレンジングするタスクに適している-あなたは気にしないところ悪いデータがあり、あなたはそれがしたいなくなって。
デフォルトでは、BFGはマルチコアマシンを最大限に活用して、コミットファイルツリーを並行してクレンジングします。git-filter-branchはコミットを順次(つまり、シングルスレッド方式で)クリーンアップ しますが、各コミットに対して実行されるスクリプトで、独自の並列処理を含むフィルターを作成することは可能です。
コマンドオプションは、はるかに制限はgit-フィルタ分岐よりも、ちょうど例えばDATA-不要の除去作業に専念します:
--strip-blobs-bigger-than 1M
。
filter-branch
ハッシュの再計算原因?大きなファイルをフィルター処理する必要があるレポでチームが作業する場合、どのようにすれば誰もが同じレポの状態になるようにできますか?
それ以降何もコミットしていない場合はgit rm
、ファイルとのみgit commit --amend
です。
あなたが持っている場合
git filter-branch \
--index-filter 'git rm --cached --ignore-unmatch path/to/file/filename.orig' merge-point..HEAD
はからmerge-point
への各変更を通過しHEAD
、filename.origを削除して変更を書き換えます。を使用--ignore-unmatch
すると、なんらかの理由でfilename.origが変更から欠落しても、コマンドは失敗しません。これはgit-filter-branchのmanページの例のセクションからの推奨される方法です。
Windowsユーザーへの注意:ファイルのパスにはスラッシュを使用する必要があります
git-filter-branch
最初のものを与えるようです。
filter-branch
"
ではなく'
、使用することを忘れないでください。そうしないと、役に立たないフレーズの「不良リビジョン」エラーが発生します。
これが最善の方法です:http :
//github.com/guides/completely-remove-a-file-from-all-revisions
最初に必ずファイルのコピーをバックアップしてください。
編集
残念ながら、Neonによる編集はレビュー中に却下されました。
以下のNeonsの投稿をご覧ください。役立つ情報が含まれている可能性があります。
たとえば、*.gz
誤ってgitリポジトリにコミットされたすべてのファイルを削除するには:
$ du -sh .git ==> e.g. 100M
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch *.gz' HEAD
$ git push origin master --force
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git gc --aggressive --prune=now
それでもうまくいきませんでしたか?(私は現在gitバージョン1.7.6.1です)
$ du -sh .git ==> e.g. 100M
マスターブランチが1つしかなかったため、理由はわかりません。とにかく、私はついにgit repoを新しい空の裸のgitリポジトリにプッシュすることで本当にクリーンアップしました。
$ git init --bare /path/to/newcleanrepo.git
$ git push /path/to/newcleanrepo.git master
$ du -sh /path/to/newcleanrepo.git ==> e.g. 5M
(はい!)
次に、それを新しいディレクトリに複製し、その.gitフォルダーをこのフォルダーに移動しました。例えば
$ mv .git ../large_dot_git
$ git clone /path/to/newcleanrepo.git ../tmpdir
$ mv ../tmpdir/.git .
$ du -sh .git ==> e.g. 5M
(ええ!ようやく片付けました!)
すべてが正常であることを確認した後、../large_dot_git
および../tmpdir
ディレクトリを削除できます(念のために、数週間または数か月後に、おそらく...)
--prune-empty
、filter-branchコマンドに追加することをお勧めします。
Git履歴を書き換えると、影響を受けるすべてのコミットIDを変更する必要があるため、プロジェクトで作業しているすべてのユーザーは、リポジトリの古いコピーを削除し、履歴をクリーンアップした後に新しいクローンを作成する必要があります。より多くのそれは不便人々 、より多くのあなたがそれを行うには十分な理由が必要-あなたの余分なファイルが問題の原因は本当にありませんが、場合にのみ、あなたプロジェクトに取り組んでいるあなたが望むなら、あなたにもGitの履歴をクリーンアップするかもしれませんに!
できるだけ簡単にするために、Git履歴からファイルを削除するために特別に設計されたものよりもシンプルで高速なBFG Repo-Cleanerを使用することをお勧めしgit-filter-branch
ます。ここでの生活を楽にする1つの方法は、デフォルトですべての参照(すべてのタグ、ブランチなど)を実際に処理することですが、10〜50倍にもなります。高速です。
:あなたは慎重にここでの手順に従ってくださいhttp://rtyley.github.com/bfg-repo-cleaner/#usage -しかし、コアビットはちょうどこのです:ダウンロードBFGジャーを(Javaの6以上が必要です)と、このコマンドを実行します:
$ java -jar bfg.jar --delete-files filename.orig my-repo.git
リポジトリ履歴全体がスキャンされ、名前が付けられたファイルfilename.orig
(最新の commitにないもの)が削除されます。これはgit-filter-branch
、同じことをするよりもかなり簡単です!
完全な開示:私はBFG Repo-Cleanerの作成者です。
You should probably clone your repository first.
Remove your file from all branches history:
git filter-branch --tree-filter 'rm -f filename.orig' -- --all
Remove your file just from the current branch:
git filter-branch --tree-filter 'rm -f filename.orig' -- --HEAD
Lastly you should run to remove empty commits:
git filter-branch -f --prune-empty -- --all
それをCharles Baileyのソリューションに追加するために、私はgit rebase -iを使用して以前のコミットから不要なファイルを削除しましたが、それは魅力のように機能しました。手順:
# Pick your commit with 'e'
$ git rebase -i
# Perform as many removes as necessary
$ git rm project/code/file.txt
# amend the commit
$ git commit --amend
# continue with rebase
$ git rebase --continue
私が見つけた最も簡単な方法は、leontalbot
(コメントとして)提案されました。これは、Anoopjohnによって公開された投稿です。答えとしてそれ自身のスペースに値すると思います:
(私はそれをbashスクリプトに変換しました)
#!/bin/bash
if [[ $1 == "" ]]; then
echo "Usage: $0 FILE_OR_DIR [remote]";
echo "FILE_OR_DIR: the file or directory you want to remove from history"
echo "if 'remote' argument is set, it will also push to remote repository."
exit;
fi
FOLDERNAME_OR_FILENAME=$1;
#The important part starts here: ------------------------
git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch $FOLDERNAME_OR_FILENAME" -- --all
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now
if [[ $2 == "remote" ]]; then
git push --all --force
fi
echo "Done."
すべてのクレジットはにAnnopjohn
、そしてleontalbot
それを指摘するために行きます。
注意
スクリプトには検証が含まれていないことに注意してください。そのため、間違いを犯さないようにしてください。また、問題が発生した場合に備えてバックアップを作成してください。それは私にとってはうまくいったが、あなたの状況ではうまくいかないかもしれない。注意して使用してください(何が起こっているのか知りたい場合は、リンクに従ってください)。
それがクリーンアップしたい最新のコミットである場合、私はgitバージョン2.14.3(Apple Git-98)で試しました:
touch empty
git init
git add empty
git commit -m init
# 92K .git
du -hs .git
dd if=/dev/random of=./random bs=1m count=5
git add random
git commit -m mistake
# 5.1M .git
du -hs .git
git reset --hard HEAD^
git reflog expire --expire=now --all
git gc --prune=now
# 92K .git
du -hs .git
git reflog expire --expire=now --all; git gc --prune=now
行うのは非常に悪いことです。ディスク容量が
これはgit filter-branch
設計されたものです。