git 履歴が次のようになっているとします。
1 2 3 4 5
1 ~ 5 は個別のリビジョンです。1、2、4、および 5 を維持したまま 3 を削除する必要があります。これはどのように行うことができますか?
削除するリビジョンの後に何百ものリビジョンがある場合、効率的な方法はありますか?
git 履歴が次のようになっているとします。
1 2 3 4 5
1 ~ 5 は個別のリビジョンです。1、2、4、および 5 を維持したまま 3 を削除する必要があります。これはどのように行うことができますか?
削除するリビジョンの後に何百ものリビジョンがある場合、効率的な方法はありますか?
このコメントによると(これが正しいことを確認しました)、 radoの答えは非常に近いですが、gitは切り離された状態のままです。代わりに、HEAD
これを削除して使用し<commit-id>
、現在のブランチから削除します。
git rebase --onto <commit-id>^ <commit-id>
削除したい<commit-id>
のみを知って、特定の を非対話的に削除する方法を次に示します。<commit-id>
git rebase --onto <commit-id>^ <commit-id> HEAD
リビジョン3と4を1つのリビジョンに結合するには、gitrebaseを使用できます。リビジョン3の変更を削除する場合は、インタラクティブリベースモードで編集コマンドを使用する必要があります。変更を1つのリビジョンに結合する場合は、スカッシュを使用します。
私はこのスカッシュテクニックをうまく使用しましたが、以前にリビジョンを削除する必要はありませんでした。「コミットの分割」の下にあるgit-rebaseのドキュメントは、うまくいけば、それを理解するのに十分なアイデアを提供するはずです。(または他の誰かが知っているかもしれません)。
gitドキュメントから:
そのまま保持したい最も古いコミットから開始します。
git rebase -i <after-this-commit>
エディターは、現在のブランチのすべてのコミット(マージコミットを無視)で起動されます。これは、指定されたコミットの後に発生します。このリストのコミットを心ゆくまで並べ替えたり、削除したりできます。リストは多かれ少なかれ次のようになります。
デッドビーを選ぶこのコミットの1行 ピックfa1afe1次のコミットの1行 ..。1行の説明は、純粋にあなたの喜びのためです。git-rebaseはそれらを確認しませんが、コミット名(この例では「deadbee」と「fa1afe1」)を確認するため、名前を削除または編集しないでください。
コマンド「pick」をコマンド「edit」に置き換えることで、そのコミットを適用した後にgit-rebaseに停止するように指示できます。これにより、ファイルやコミットメッセージを編集し、コミットを修正して、リベースを続行できます。
2つ以上のコミットを1つに折りたたむ場合は、2番目以降のコミットでコマンド「pick」を「squash」に置き換えます。コミットに異なる作成者がいた場合、押しつぶされたコミットは最初のコミットの作成者に帰属します。
前に述べたように、git-rebase(1)はあなたの友達です。コミットがmaster
ブランチにあると仮定すると、次のようになります。
git rebase --onto master~3 master~2 master
前:
1---2---3---4---5 master
後:
1---2---4'---5' master
git-rebase(1)から:
コミットの範囲は、リベースで削除することもできます。次のような状況の場合:
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の引数とパラメーターは、任意の有効なcommit-ishにすることができることに注意してください。
リビジョン 3 で行われた変更を削除するだけの場合は、git revert を使用することをお勧めします。
Git revert は、元に戻すリビジョンのすべての変更を元に戻す変更を含む新しいリビジョンを作成するだけです。
これが意味することは、不要なコミットと、それらの変更を削除するコミットの両方に関する情報を保持するということです。
元に戻すことは基本的に単なる標準的なコミットであるため、その間に誰かがあなたのリポジトリからプルした可能性がある場合、これはおそらくはるかに友好的です。
これまでのすべての回答は、後続の懸念に対処していません。
削除するリビジョンの後に何百ものリビジョンがある場合、効率的な方法はありますか?
手順は次のとおりですが、参考までに、次の履歴を想定してみましょう。
[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]
C : 削除するコミットの直後にコミットする (クリーン)
R : 削除するコミット
B : 削除するコミットの直前のコミット (ベース)
「何百ものリビジョン」という制約があるため、次の前提条件を想定しています。
これはかなり制限的な制約のセットですが、このコーナー ケースで実際に機能する興味深い答えがあります。
手順は次のとおりです。
git branch base B
git branch remove-me R
git branch save
git rebase --preserve-merges --onto base remove-me
本当に競合がない場合は、これ以上中断することなく続行する必要があります。対立がある場合は、それらを解決するrebase --continue
か、恥ずかしさと一緒に暮らすことを決定できますrebase --abort
。
これで、コミットRmaster
がなくなった状態になるはずです。和解したい場合に備えて、ブランチは以前の場所を指しています。save
新しい歴史への他の全員の転送をどのように手配したいかは、あなた次第です。stash
、reset --hard
、およびに精通している必要がありcherry-pick
ます。base
そして、、、remove-me
およびsave
ブランチを削除できます
rado と kareem の回答は私には何もしません (「Current branch is up to date.」というメッセージのみが表示されます)。これは、Windows コンソールで '^' 記号が機能しないために発生する可能性があります。ただし、このコメントによると、「^」を「~1」に置き換えると問題が解決します。
git rebase --onto <commit-id>^ <commit-id>