私はずっと前から悪いコミットを持っています、私はそれが決して起こらなかったかのようにそれをgit履歴から完全に削除したいと思います。私はコミットIDを知っています。たとえば1f020です。私はgitrebaseを試し、それを削除しましたが、リベース時に非常に多くの競合が発生するため、その方法では不可能です。そのコミットは、コードの単純な1行の変更であり、プロジェクトに関係のないいくつかのファイルをプッシュします。だから私はその1行のコード変更を書いてそれをコミットし、それからどういうわけかこの新しいコミットをずっと前のものに置き換えたいと思います。
4 に答える
問題のあるコミットがプライベート リポジトリにある場合、何をしたいかは大したことではありません。公開された git 履歴を書き換えることは共同作業者にとってイライラするので、この行を削除する価値があることを確認してください。
git-rebase
ドキュメントには役立つ一節があります。
git rebase [...] [<--onto newbase>] [<upstream>] [<branch>]
リベースを使用して、一連のコミットを削除することもできます。次のような状況の場合:
E---F---G---H---I---J topicA
次に、コマンド
git rebase --onto topicA~5 topicA~3 topicA
コミットFおよびGが削除されます。
E---H'---I'---J' topicA
これは、 FとGに何らかの欠陥がある場合、または の一部であってはならない場合に役立ち
topicA
ます。への引数--onto
と上流のパラメータは、有効なコミットっぽいものであれば何でもよいことに注意してください。
履歴が直線的で、問題のあるコミットがマスター ブランチにあると仮定すると、上記の例を実行して適応させることができます。
git rebase --onto 1f020~ 1f020 master
複雑な状況では、インタラクティブなリベースを使用してください。2 つのコミットをマージする例に従うと役立つ場合がありますが、コミットを for squash でマークする代わりに、s
行全体を削除して履歴からコミットを削除します。
これは少し複雑ですが、とにかく、次のようになります。
頭を切り離し、その悪いコミットの直後にコミットするように移動します。git log を使用して、1f020 以降の次のコミットを見つけます。
git checkout <SHA1-for-commit-just-after-bad-commit-1f020>
その悪いコミットの直前にHEADをコミットするように移動しますが、インデックスと作業ツリーはそのままにしておきます
git reset --soft <SHA1-for-just-previous-to-bad-commit-1f020>
コミットメッセージを再利用してその悪いコミットの直後にコミットをやり直しますが、今はその悪いコミットの直前にコミットします。したがって、その悪いコミットを削除します
git commit -C <SHA1-for-commit-just-after-bad-commit-1f020>
この新しい場所への悪いコミットの直後のコミットからすべてを再適用します
git rebase --onto HEAD <SHA1-for-commit-just-after-bad-commit-1f020> master
git の履歴からコミットを削除しないでください。後で問題が発生します。
しかし、自分が何をしているのかわかっている場合は、履歴をローカルに巻き戻し、そのコミットを現在のコミットに置き換えてから、すべてのコミットをもう一度再生してから、リポジトリに強制的にプッシュすることができます。
しかし、私はこれに反対することを強くお勧めします. 新しいコミットを行い、歴史に悪いコミットがあることを生きてください。
だから、あなたがしたいのは:
履歴から悪いコミットを削除し、
削除されたコミットの後に行われたすべてのマージをやり直す必要はありません。つまり、削除されたコミットから派生した各コミットはそのまま保持する必要があり、履歴から消去された変更を含まないように最小限の変更のみを行う必要があります。
2 番目のポイントに基づくソリューションgit rebase --onto
とgit rebase -i
失敗するソリューションは、後で発生したすべてのマージをやり直す必要があるためです。ただし、問題のあるコミットが発生しなかったかのように、これらの他のすべてのコミットを単純に再作成することは理論的には可能です。
Michael と他の人が指摘したように、これを行うことは非常にお勧めできません。それはまた、ほぼ確実に努力する価値のない大事業でもあります。ただし、教育の価値については、目標を達成するための包括的なソリューションの概要を次に示します。
リポジトリをバックアップします。
git rev-list
不正なコミットから始まり、コミットに到達できるすべてのブランチ ヘッドに至るまでのコミットのリストを生成するために使用します。空のマップを初期化して、古いコミットを新しいコミットにマップします。
リスト内のコミットごとに、次の操作を行います。
- コミットをチェックアウトし、悪いコミットからの変更を元に戻します
- を使用して現在のツリーからツリー オブジェクトを作成する
git write-tree
git commit-tree
新しいツリー、古いコミット メッセージ、および上記のマップを使用して古い親から変換された親で新しいコミットを作成するために使用します (一部の親がマップにない場合は、古い親を使用してください) 。- 新しいコミットをコミット マップに登録します。
タグとタグ オブジェクトを調べ、それらを再作成して新しいコミットを指すようにし、マップを調べます。
ブランチ ヘッドを
git update-ref
調べて、新しいコミットを指すように呼び出し、マップを調べます。
コミットによって導入された 1 行の変更 (および不要なファイル) が後のコミットからの変更と競合しない場合、このプロセスは完全に自動化される可能性があり、後ですべてのマージと競合を手動でやり直す必要はありません。コミットします。
欠点は、その後のすべてのコミットを書き直す必要があり、他の場所で共有されていた場合はそれらを無効にし、 によって生成されるようなコミット メッセージ内のコミット参照を無効にすることgit revert
です。