変更を保持しながら、Gitリポジトリから選択したコミットログエントリを削除する方法


241

選択したコミットログエントリを線形コミットツリーから削除して、エントリがコミットログに表示されないようにします。

私のコミットツリーは次のようになります。

R--A--B--C--D--E--HEAD

BエントリとCエントリを削除して、コミットログに表示されないようにしたいのですが、AからDへの変更は保持する必要があります。たぶん、単一のコミットを導入することで、BとCがBCになり、ツリーは次のようになります。

R--A--BC--D--E--HEAD

または、理想的には、Aの後にDが直接来る。Dは、AからB、BからC、CからDへの変化を表します。

R--A--D'--E--HEAD

これは可能ですか?はいの場合、どのように?

これはかなり新しいプロジェクトなので、現時点ではブランチがなく、したがってマージもありません。


@ xk0der:ここでは「コミット」が正しい用語です。rebase古い/新しいコミットを削除するかもしれません。「commit log entry」の意味がわかりません。
jfs

@JFSebastian「コミットログ」に問題がありません-すべてのコミットのログ。そして、実際の変更(コミット)を維持しながら、ログからいくつかのエントリを削除したかったのです。
xk0der

@ xk0der:gitコミットはコンテンツアドレス指定可能です。つまり、ログメッセージなど、コミットで何かを変更した場合。新しいコミットを作成します。gitなしでgitのコミットを読んで、自分で確認することができます
jfs

@JFSebastian-リンクをありがとう-私は知っています-しかし、その技術は私が直面していた問題と私がそれをどのように提示したかを本当に変えますか?私はそうは思いません。最後に、「コミットの変更」を削除せずに「コミットログメッセージ」を削除したかった-私の質問をもう一度読んでください-特に2番目の段落。さらにgit logショーを追加するには、「コミットログ」git-scm.com/docs/git-logを使用します。また、変更ではなく、そのログから2つのエントリを削除したかったのです。
xk0der

回答:


273

git-rebase(1)はまさにそれを行います。

$ git rebase -i HEAD~5

git awsome-ness [git rebase --interactive]に例が含まれています。

  1. git-rebaseパブリック(リモート)コミットでは使用しないでください。
  2. 作業ディレクトリがクリーン(commitまたはstash現在の変更)であることを確認してください。
  3. 上記のコマンドを実行します。を起動します$EDITOR
  4. 置き換えpickCDsquash。CとDをBに統合します。コミットを削除する場合は、その行を削除してください。

道に迷った場合は、次のように入力します。

$ git rebase --abort  

早速のお返事ありがとうございます。それで、私はAをチェックアウトしてリベースを行いgit rebase -i D [A]ますか?
xk0der 2009年


3
リモートリポジトリでどうすればよいですか?
Eray、2011年

6
@Eray:ただpush -fあなたの変更。あなたが一人で働いていないのなら、それをしないでください。
jfs

2
@ ripper234:git-rebaseブログ投稿のポイントマニュアルとウェイバックマシンへのリンクを修正しました。
jfs

75
# detach head and move to D commit
git checkout <SHA1-for-D>

# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>

# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>

# Re-apply everything from the old D onwards onto this new place 
git rebase --onto HEAD <SHA1-for-D> master

これも機能し、ソフトリセットとは何かを理解するのに役立ちました。確かに、「トップ」の回答も正しく、短くなっていますが、この回答にも感謝します。
cgp

41

削除したいコミットIDだけがわかっている特定のコミットIDを削除する方法を次に示します。

git rebase --onto commit-id^ commit-id

これにより、実際にはコミットによって導入された変更が削除されることに注意してください。


7
このコマンドに余分なHEADがあると、リベースが望ましくない「デタッチされたHEAD」で終了します。省略してください。
フロスティ

3
これにより、commit-idで導入された変更が元に戻ります。OPは変更を保持したいので、コミットを破棄します。
CBベイリー

1
-1は、OPが要求したことを行わないためです(むしろ、明示的に保持したいものを破棄します)。
Emil Styrke 2013年

1
OPが要求したことを行うものではありませんが、それはまさに私が必要とするものでした。
Edvins

20

JFセバスチャンの答えを拡張するには:

git-rebaseを使用すると、コミット履歴にあらゆる種類の変更を簡単に加えることができます。

git rebase --interactiveを実行すると、$ EDITORに次のようになります。

pick 366eca1 This has a huge file
pick d975b30 delete foo
pick 121802a delete bar
# Rebase 57d0b28..121802a onto 57d0b28
#
# 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

行を移動してコミットの順序を変更し、行を削除してそのコミットを削除できます。または、2つのコミットを結合(スカッシュ)して1つのコミット(以前のコミットは上記のコミットです)、編集コミット(変更内容)、またはコミットメッセージを言い換えるコマンドを追加できます。

ピックとは、そのコミットをそのままにしておきたいという意味です。

(例はこちらから)


14

次のコマンドを使用して、例のBとCを非対話的に削除できます。

git rebase --onto HEAD~5 HEAD~3 HEAD

または象徴的に、

git rebase --onto A C HEAD

BとCの変更はDには反映されないことに注意してください。彼らはなくなるでしょう。


詳しくはこちらをご覧ください:sethrobertson.github.io/GitFixUm/fixup.html#remove_deep
最大

3

もう1つの方法は、

git rebase -i ad0389efc1a79b1f9c4dd6061dca6edc1d5bb78a (C's hash)
and
git push origin master  -f

ベースとして使用するハッシュを選択し、上記のコマンドでインタラクティブにする必要があります。これにより、すべての上位メッセージを押しつぶすことができます(最も古いメッセージを残す必要があります)


2

AのSHA1から別のブランチを作成し、必要な変更をチェリーピックすることで、このプロセスがはるかに安全で理解しやすくなるので、この新しいブランチの外観に満足できることを確認できます。その後、古いブランチを削除して新しいブランチの名前を変更するのは簡単です。

git checkout <SHA1 of A>
git log #verify looks good
git checkout -b rework
git cherry-pick <SHA1 of D>
....
git log #verify looks good
git branch -D <oldbranch>
git branch -m rework <oldbranch>

これを行うと、Eコミットも失われますね。私が理解しているように、マスターを削除し、リワークの名前をマスターに変更します(ABCDEフローがマスターブランチであることを考慮して)。
Renan Bandeira 2016

1

すべての人の答えを集めました:(git plzの新機能は参照用にのみ使用してください)

コミットを削除するgit rebase

git log

-first check from which commit you want to rebase

git rebase -i HEAD〜1

-Here i want to rebase on the second last commit- commit count starts from '1')
-this will open the command line editor (called vim editor i guess)

次に、画面は次のようになります。

pick 0c2236d新しい行を追加しました。

2a1cd65..0c2236dを2a1cd65にリベース(1コマンド)

コマンド:

p、pick =コミットを使用

r、reword =コミットを使用しますが、コミットメッセージを編集します

e、編集=コミットを使用しますが、修正のために停止します

s、squash =コミットを使用しますが、以前のコミットにマージします

f、fixup = "squash"に似ていますが、このコミットのログメッセージを破棄します

x、exec =シェルを使用してコマンド(行の残りの部分)を実行する

d、ドロップ=コミットを削除

これらの行は並べ替えることができます。それらは上から下に実行されます。

ここで行を削除すると、そのコミットは失われます。

ただし、すべてを削除すると、リベースは中止されます。

空のコミットはコメントアウトされていることに注意してください〜〜









ここで、必要に応じて最初の行を変更します(上記のコマンド、つまり「drop」を使用してコミットなどを削除します)。編集が完了したら、「:x」を押して保存し、エディターを終了します(これはvimエディター専用です)。

その後

git push

問題が発生している場合は、変更をリモートに強制的にプッシュする必要があります(ITS VERY CRITICAL:チームで作業している場合は、強制的にプッシュしないでください)。

git push -f origin


-1

これにはgit cherry-pickを使用できます。'cherry-pick'は今すぐブランチにコミットを適用します。

それから

git rebase --hard <SHA1 of A>

次に、DおよびEコミットを適用します。

git cherry-pick <SHA1 of D>
git cherry-pick <SHA1 of E>

これにより、BおよびCコミットがスキップされます。BなしでブランチにDコミットを適用することは不可能かもしれないと述べたので、YMMVです。


2
OPは、変更を削除するのではなく、B、C、Dのコミットを組み合わせたいと考えています。
jfs 2009

3
(存在しない)ではなくreset --hard、を意味していると思いますrebase --hard
Mauricio Scheffer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.