成功した「git cherry-pick」を元に戻す方法は?


96

ローカルリポジトリでは、git cherry-pick SHA競合や問題なく実行されました。その後、私は今したいことをしたくないと気づきました。私はこれをどこにも押していません。

このチェリーピックだけを削除するにはどうすればよいですか?

これを行う方法があるかどうか知りたい:

  • 他の地域の変更があるとき
  • 他にローカルな変更がない場合

できれば両方のケースで1つのコマンドを使用することをお勧めします。

回答:


131

チェリーピックは基本的にコミットなので、元に戻したい場合はコミットを取り消すだけです。

他の地域の変更があるとき

現在の変更を隠しておくと、コミットをリセットした後で再適用できます。

$ git stash
$ git reset --hard HEAD^
$ git stash pop  # or `git stash apply`, if you want to keep the changeset in the stash

他にローカルな変更がない場合

$ git reset --hard HEAD^

6
質問と回答に加えて、何を選んでいるのかわからない場合は、いつでも「チェリーピックSHA --no-commit」を実行できます。簡単にチェックアウトできるコミットのみの変更はありません。 、これは部分的なチェリーピッキングに便利です
kuskmen 2017

1
windows:git reset --hard "HEAD ^"
スリムな

21

最後のコミットを取り消すには、単にを実行しますgit reset --hard HEAD~

編集:この回答は、ローカルの変更の保持について言及していなかった以前のバージョンの質問に適用されました。ティムから受け入れられた答えは確かに正しいものです。頭を上げてくれたqwertzguyに感謝します。


2
それはHEAD ^または
HEAD〜1である

これらはどちらもHEAD〜(およびそのことについてはHEAD ^ 1)と同等です
David Deutsch

1
@DavidDeutsch確かにそうです(ただし、Gitの最近のバージョンでのみ)。大文字(HEAD)の方が堅牢ですhead。は、既存の参照の名前がであるという不幸なケースを考慮してください。
jub0bs

1
@Jubobs-良い点; 答えの大文字と小文字を変更しました。
David Deutsch 2015年

1
@qwertzguy、良いキャッチ。タイムスタンプを見ると、この回答を投稿してから1分後にローカルの変更に関するビットが質問に追加されました:)
David Deutsch

8

可能であれば、ハードリセットを避けてください。ハードリセットは、gitで非常に少数の破壊的な操作の1つです。幸いにも、リセットせずにチェリーピックを取り消すことができ、破壊的なものを回避できます。

取り消したいチェリーピックのハッシュに注意してください${bad_cherrypick}。を行いますgit revert ${bad_cherrypick}。これで、作業ツリーの内容は、悪いチェリーピックの前と同じです。

を繰り返しgit cherry-pick ${wanted_commit}、新しいチェリーピックに満足したら、を実行しgit rebase -i ${bad_cherrypick}~1ます。リベース中に、両方${bad_cherrypick}とそれに対応する復帰を削除します。

あなたが取り組んでいるブランチは、良いチェリーピックしかありません。リセットは必要ありません!


6

git reflog あなたの助けに来ることができます。

コンソールに入力すると、git履歴のリストとSHA-1が表示されます。

元に戻したいSHA-1をチェックアウトするだけです


答える前に、背景を追加し、これが何であるかを説明しましょうHEAD

First of all what is HEAD?

HEAD現在のブランチ上の現在のコミット(最新)への参照です。
一度に存在できるのは1つだけHEADです。(除くgit worktree

の内容HEADは内部に格納され.git/HEAD、現在のコミットの40バイトのSHA-1が含まれています。


detached HEAD

あなたが最新のコミットをしていない場合-それHEADは、それが呼び出された履歴内の以前のコミットを指していることを意味しdetached HEADます。

ここに画像の説明を入力してください

コマンドラインでHEADは、は現在のブランチの先端を指していないため、ブランチ名の代わりにSHA-1のようになります。

ここに画像の説明を入力してください

ここに画像の説明を入力してください

切り離されたヘッドから回復する方法に関するいくつかのオプション:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

これにより、目的のコミットを指す新しいブランチがチェックアウトされます。
このコマンドは、指定されたコミットにチェックアウトします。
この時点で、ブランチを作成して、この時点から作業を開始できます。

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

いつでも使用できreflogます。
git reflog更新された変更が表示さHEADれ、目的のreflogエントリをチェックアウトすると、HEADこのコミットに戻ります。

HEADが変更されるたびに、新しいエントリが reflog

git reflog
git checkout HEAD@{...}

これにより、目的のコミットに戻ります

ここに画像の説明を入力してください


git reset --hard <commit_id>

HEADを目的のコミットに「移動」します。

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • 注:(Git 2.7以降
    も使用できgit rebase --no-autostashます。

git revert <sha-1>

指定されたコミットまたはコミット範囲を「元に戻す」。
リセットコマンドは、指定されたコミットで行われた変更を「取り消し」ます。
元に戻すコミットを含む新しいコミットはコミットされますが、元のコミットも履歴に残ります。

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

このスキーマは、どのコマンドが何を実行するかを示しています。
ご覧のとおり、をreset && checkout変更しHEADます。

ここに画像の説明を入力してください


おそらく追加git reset --hard
wyx

3

これと同じ問題に直面し、チェリーピックが成功してからコミットまたはリモートにプッシュしたことがあり、それを削除したい場合は、次のコマンドを実行してチェリーピックのSHAを見つけることができます。

git log --graph --decorate --oneline

次に、(:wqログの終了に使用した後)を使用してチェリーピックを削除できます

git rebase -p --onto YOUR_SHA_HERE^ YOUR_SHA_HERE

ここでYOUR_SHA_HERE、厳選されたコミットの40文字または省略された7文字のSHAと同じです。

最初は、リモートリポジトリとローカルリポジトリのコミット履歴が異なるため、変更をプッシュすることはできません。次のコマンドを使用して、ローカルコミットを強制してリモートの内容を置き換えることができます

git push --force origin YOUR_REPO_NAME

(私はSeth Robertsonからこのソリューションを採用しました:「コミット全体の削除」を参照してください。)


1

1つのコマンドで破壊的なコマンドを使用しないgit reset

GIT_SEQUENCE_EDITOR="sed -i 's/pick/d/'" git rebase -i HEAD~ --autostash

それは単にコミットをドロップし、ローカルで変更があったとしてもチェリーピックの前の状態に正確に戻します。


それは単にコミットを落とすだけです。どう思いますgit reset HEAD^
Tim

@TimCastelijns git resetは、変更を削除せずにコミットアクションを取り消します。git-scm.com/docs/git-resetを読むことをお勧めします。OPからの質問は、チェリーピックを元に戻すことです。両方のコマンドを試してください。私の場合は、チェリーピックの前の状態に戻ります。git resetチェリーピックされた変更を残し、既存のローカル変更と区別がつかなくなると、作業ツリーがめちゃくちゃになります。
qwertzguy 2017年

はい、ごめんなさい、私は意味しましたreset --hard。変更はありません
Tim

1
@TimCastelijns git reset --hardは、関連のないローカル変更も削除し、回復不能な方法で削除する破壊的なコマンドです!したがって、それはOPが要求したものではありません。
qwertzguy 2017年

2
この回答は、そのsedコマンドが何をしているか、それを手動で行うのとどのように違うのか、そして何をするのかを説明した方がはるかに役立ちます--autostash
クリスページ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.