他の開発者に履歴を公開している場合、あなたがしたいことは非常に破壊的です。履歴を修復した後に必要な手順については、git rebase
ドキュメントの「アップストリームリベースからの回復」を参照してください。
少なくとも2つのオプションがあります。1つgit filter-branch
はインタラクティブリベースで、どちらも以下で説明します。
使用する git filter-branch
Subversionインポートからのかさばるバイナリテストデータで同様の問題があり、gitリポジトリからのデータの削除について書いています。
あなたのgit履歴が次のとおりだとしましょう:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
注git lola
非標準が、非常に便利な別名です。では--name-status
スイッチ、我々はそれぞれのコミットに関連付けられたツリーの変更を見ることができます。
「Careless」コミット(SHA1オブジェクト名はce36c98)では、ファイルoops.iso
は誤って追加され、次のコミットcb14efdで削除されたDVDリップです。前述のブログ投稿で説明されている手法を使用すると、実行するコマンドは次のとおりです。
git filter-branch --prune-empty -d /dev/shm/scratch \
--index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
--tag-name-filter cat -- --all
オプション:
--prune-empty
フィルター操作の結果として空になった(つまり、ツリーを変更しない)コミットを削除します。典型的なケースでは、このオプションはより明確な履歴を生成します。
-d
フィルタリングされた履歴の構築に使用する、まだ存在していない一時ディレクトリを指定します。最新のLinuxディストリビューションで実行している場合、でツリーを/dev/shm
指定すると、実行が速くなります。
--index-filter
メインイベントであり、履歴の各ステップでインデックスに対して実行されます。oops.iso
見つかった場所はどこでも削除したいが、すべてのコミットに存在するわけではない。このコマンドgit rm --cached -f --ignore-unmatch oops.iso
はDVD-ripが存在する場合はそれを削除し、それ以外の場合は失敗しません。
--tag-name-filter
タグ名を書き換える方法を説明します。のフィルターcat
は、アイデンティティー操作です。上記のサンプルのように、リポジトリにはタグがない可能性がありますが、完全な一般性のためにこのオプションを含めました。
--
オプションの終わりを指定します git filter-branch
--all
以下--
はすべての参照の省略形です。上記のサンプルのように、リポジトリには参照(マスター)が1つしかない場合がありますが、このオプションは一般性を高めるために含めました。
いくつかの攪拌の後、歴史は今です:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A login.html
| * cb14efd Remove DVD-rip
| | D oops.iso
| * ce36c98 Careless
|/ A oops.iso
| A other.html
|
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
新しい「Careless」コミットは追加されるだけでother.html
あり、「Remove DVD-rip」コミットはマスターブランチには存在しないことに注意してください。ラベルrefs/original/refs/heads/master
が付けられたブランチには、ミスをした場合の元のコミットが含まれています。削除するには、「リポジトリを縮小するためのチェックリスト」の手順に従ってください。
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
より簡単な方法として、不要なビットを破棄するためにリポジトリを複製します。
$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo
file:///...
クローンURL を使用すると、ハードリンクのみを作成するのではなく、オブジェクトをコピーします。
今あなたの歴史は:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
フィルター操作でこれらのコミットが変更されなかったため、最初の2つのコミット(「インデックス」と「管理ページ」)のSHA1オブジェクト名は同じままでした。「Careless」が失われoops.iso
、「Login page」が新しい親を取得したため、SHA1 は変更されました。
インタラクティブなリベース
の歴史を持つ:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
oops.iso
追加したことがないかのように「Careless」から削除したい場合、「Remove DVD-rip」は役に立たない。したがって、インタラクティブなリベースに入る私たちの計画は、「管理ページ」を維持し、「注意せず」を編集して、「DVDリップの削除」を破棄することです。
実行$ git rebase -i 5af4522
すると、以下の内容でエディターが起動します。
pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
計画を実行し、それを次のように変更します。
edit ce36c98 Careless
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
# ...
つまり、「Remove DVD-rip」で行を削除し、「Careless」の操作をedit
ではなくに変更しますpick
。
エディターを保存して終了すると、コマンドプロンプトに次のメッセージが表示されます。
Stopped at ce36c98... Careless
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
メッセージが示すように、私たちは編集したい「Careless」コミットを実行しているので、2つのコマンドを実行します。
$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue
1つ目は、問題のあるファイルをインデックスから削除します。2番目は、「Careless」を更新されたインデックスになるように変更または修正し-C HEAD
、古いコミットメッセージを再利用するようにgitに指示します。最後に、git rebase --continue
残りのリベース操作に進みます。
これはの歴史を与えます:
$ git lola --name-status
* 93174be (HEAD, master) Login page
| A login.html
* a570198 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
あなたが望むのはそれです。