git履歴の特定のリビジョンをどのように削除しますか?


213

gitの履歴が次のようになっているとします。

1 2 3 4 5

1–5は個別のリビジョンです。1、2、4、5を維持したまま3を削除する必要があります。これを行うにはどうすればよいですか?

削除するリビジョンの後に何百ものリビジョンがある場合、効率的な方法はありますか?


この質問は不明確です。著者が1-2-(3 + 4)-5または1-2-4-5を望んでいることを明確に述べていません
RandyTek

14
さて8年後、私が解決しようとしていた問題を正確に伝えることはできません。しかし、gitには常に何かを行うための多くの方法があり、さまざまな人々が好んだ多くの答えがあるので、あいまいさが多くの人々にそれほど大きな問題を引き起こしていないと思います
1800情報

1
git rebase --onto 2 3 HEADほぼ3とHEADの間のコミットで2にリベースすることを意味します(HEADはオプション、この場合は5)
neaumusic

回答:


76

リビジョン3と4を1つのリビジョンに結合するには、git rebaseを使用できます。リビジョン3の変更を削除する場合は、インタラクティブリベースモードで編集コマンドを使用する必要があります。変更を1つのリビジョンに結合する場合は、スカッシュを使用します。

私はこのスカッシュテクニックをうまく使用しましたが、以前にリビジョンを削除する必要はありませんでした。「Splitting commits」の下にあるgit-rebaseのドキュメントは、それを理解するのに十分なアイデアを提供してくれるはずです。(または他の誰かが知っているかもしれません)。

gitドキュメントから:

そのまま保持したい最も古いコミットから始めます。

git rebase -i <after-this-commit>

エディターは、現在のブランチ(マージコミットは無視)内のすべてのコミットで起動されます。これらのコミットは、指定されたコミットの後に来ます。このリストのコミットを思い通りに並べ替えたり、削除したりできます。リストは多かれ少なかれこのように見えます:

pickdeadbeeこのコミットの1行
pick fa1afe1次のコミットの1行
...

onelineの説明は、純粋にあなたの喜びのためのものです。git-rebaseはそれらを参照せず、コミット名(この例では「deadbee」と「fa1afe1」)を参照するため、名前を削除または編集しないでください。

コマンド「pick」をコマンド「edit」に置き換えることで、そのコミットの適用後に停止するようにgit-rebaseに指示できるため、ファイルやコミットメッセージを編集し、コミットを修正して、リベースを続行できます。

2つ以上のコミットを1つにまとめたい場合は、2回目以降のコミットの「pick」コマンドを「squash」に置き換えます。コミットの作成者が異なる場合、つぶされたコミットは最初のコミットの作成者に帰属します。


42
-1問題は明確に定義されていますが、この答えはそれほど明確ではありません。著者は正確な解決策が何であるかを述べていません。
Aleksandr Levchuk

1
これは間違ったリードです。SPLITTING COMMITSセクションは正しくありません。マニュアルをもっと読みたい-@Rares Vernicaの答えを見てください。
Aleksandr Levchuk

1
@AleksandrLevchuk質問は明確に定義されていません:3のチェンジセットを保持するか破棄するかという質問の記述方法からは不明です。変更が破棄される場合、他の回答がより簡単なアプローチを提供することに同意します。ただし、変更を保持する場合、これは純粋に美容上の操作です。どちらのアプローチも、他の人が欠陥のある履歴に基づいて作業を行っている場合に危険な方法で履歴を書き換えます。その場合は、表面的なクリーンアップを行わないでください。変更の削除は、git revertを使用して行うことをお勧めします。
セオドアマードック

124

パーこのコメント(と私はこれが真実であることを確認)、ラドーの答えは非常に近いですが、葉は切り離さヘッド状態ではgit。代わりに、HEADこれを削除<commit-id>して使用して、現在のブランチから削除します。

git rebase --onto <commit-id>^ <commit-id>

1
commit-idだけに基づいて履歴からそのcommit-idを削除する方法を教えていただければ、あなたは私のヒーローになります。
kayleeFrye_onDeck 2016

魔法のコマンドが何をするかの説明を答えに含めていただけませんか?つまり、各パラメータは何を示していますか?
alexandroid

これは素晴らしいですが、履歴の最初のコミットを削除したい場合はどうなりますか?(これが私がここに来た理由です:P)
スターリングカムデン

2
何らかの理由で、これを実行しても何も起こりません。ただし、動作する^ように変更し~1ます。
アンチモン2017年

かなり遅いですが、マージの競合が発生した場合は、リベースを中止し--strategy-option theirsて、最後に再実行してください。
LastStar007

122

以下は、非対話的に特定のを削除する方法です。削除するの<commit-id>は自分だけ<commit-id>です。

git rebase --onto <commit-id>^ <commit-id> HEAD

2
私も働いた。ところで、^演算子は何をしますか?指定されたコミットの次のコミットを意味しますか?
ホピア2012

3
@hopiaこれは、指定されたコミットの(最初の)親を意味します。「git help revisions」を参照してください
Emil Styrke 2013年

12
HEAD頭が外れないように、@ kareemの省略の回答を参照してください。
mklement0 2013

1
検索に戻るコミットの数を把握する必要があるよりもはるかに簡単です。
Dana Woodman 2013年

1
これは素晴らしいですが、履歴の最初のコミットを削除したい場合はどうなりますか?(これが私がここに来た理由です:P)
スターリングカムデン

76

前述のように、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
これはいけません--onto master~3 master~1か?
Matthias

3
最後のコミットを単に削除したい場合は、-onto master〜1 master
MikeHoss

このゾルを持っていきたいです。私は取得MERGE CONFLICTエラー。私はstackoverflow.com/questions/2938301/remove-specific-commitに記載されているシナリオを使用しましたが、その例では2番目のコミットを削除できません。
maan81

22

リビジョン3で行った変更を削除するだけの場合は、git revertを使用できます。

Git revertは、元に戻すリビジョンのすべての変更を取り消す変更を含む新しいリビジョンを作成するだけです。

これは、不要なコミットとそれらの変更を削除するコミットの両方に関する情報を保持することを意味します。

元に戻す操作は基本的に標準のコミットに過ぎないので、誰かがあなたのリポジトリからその間引っ張ってきたとしたら、これはおそらくもっと友好的です。


4
残念ながら、誰かが誤って100MBのがらくたをリポジトリにコミットしてしまい、サイズが大きくなり、Webインターフェースが遅くなるため、私にとっては適切な解決策ではありません。
スティーブンスミス

18

これまでのすべての回答は、末尾の懸念に対処していません。

削除するリビジョンの後に何百ものリビジョンがある場合、効率的な方法はありますか?

手順は次のとおりですが、参考のために、次の履歴を想定します。

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]

C:削除するコミットの直後にコミット(クリーン)

R:削除するコミット

B:削除するコミットの直前のコミット(ベース)

「何百もの改訂」制約のため、私は次の前提条件を想定しています。

  1. あなたが決して存在しないことを望むいくつかの恥ずかしいコミットがあります
  2. その恥ずかしいコミットに実際に依存する後続のコミットはゼロです(復帰時の競合はゼロ)
  3. 何百もの介在するコミットの「コミッター」としてリストされることを気にしません(「作者」は保持されます)
  4. リポジトリを共有したことがない
    • または、実際には、コミットメントを使用して履歴を複製したすべての人々に十分な影響力があり、新しい履歴を使用するように説得します
    • そして、あなたは気にしないについての歴史を書き換えます

これはかなり制限的な制約のセットですが、このコーナーケースで実際に機能する興味深い答えがあります。

手順は次のとおりです。

  1. git branch base B
  2. git branch remove-me R
  3. git branch save
  4. git rebase --preserve-merges --onto base remove-me

本当に競合がない場合は、これ以上の中断はありません。衝突がある場合は、それらを解決するか、rebase --continueまたは恥ずかしさやrebase --abort

これでmaster、コミットRがなくなったはずです。saveあなたが調整したい場合には、前にいた場所への分岐点。

他の全員の新しい履歴への転送をどのように手配するかはあなた次第です。あなたは精通する必要がありますstashreset --hardcherry-pick。そして、あなたは削除することができbaseremove-meおよびsave枝を


これを150000回好きにするにはどうすればよいですか?
Gena Moroz、2015年

私が働いて、誰かが150 mbファイルの束をコミットしたブランチの履歴の途中から3つのコミットを順番に削除しました。
Marcos

3

私も同じような状況で上陸しました。以下のコマンドを使用してインタラクティブなリベースを使用し、3番目のコミットを選択してドロップします。

git rebase -i remote/branch

2

これが私が直面したシナリオと、それをどのように解決したかです。

[branch-a]

[Hundreds of commits] -> [R] -> [I]

これRは私が削除する必要があったコミットであり、I後に来る単一のコミットですR

私は元に戻すコミットを行い、それらを一緒に押しつぶしました

git revert [commit id of R]
git rebase -i HEAD~3

インタラクティブなリベースのスカッシュ中に、最後の2つのコミット。


0

radoとkareemの応答は何もしません(「現在のブランチは最新です。」というメッセージのみが表示されます)。これは、「^」記号がWindowsコンソールで機能しないために発生する可能性があります。ただし、このコメントによると、「^」を「〜1」に置き換えると問題が解決します。

git rebase --onto <commit-id>^ <commit-id>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.