「git commit」の代わりに「git commit --amend」を元に戻す方法


1295

以前のコミットを誤って修正しました。特定のファイルに加えた変更の履歴を保持するには、コミットを個別にする必要がありました。

最後のコミットを元に戻す方法はありますか?のようなことをするgit reset --hard HEAD^と、最初のコミットも元に戻されます。

(私はまだリモートディレクトリにプッシュしていません)

回答:


2291

現在のHEADコミットと同じ詳細で、親を以前のバージョンのとして新しいコミットを作成する必要がありますHEADgit reset --soft次のコミットが現在のブランチヘッドのある場所とは異なるコミットの上で行われるように、ブランチポインタを移動します。

# Move the current head so that it's pointing at the old commit
# Leave the index intact for redoing the commit.
# HEAD@{1} gives you "the commit that HEAD pointed at before 
# it was moved to where it currently points at". Note that this is
# different from HEAD~1, which gives you "the commit that is the
# parent node of the commit that HEAD is currently pointing to."
git reset --soft HEAD@{1}

# commit the current tree using the commit details of the previous
# HEAD commit. (Note that HEAD@{1} is pointing somewhere different from the
# previous command. It's now pointing at the erroneously amended commit.)
git commit -C HEAD@{1}

33
とてもクールです、+ 1。最後の2番目の修正ビューを使用git reflogして、正しい番号を見つけることも行いました{2}
JJD 2011

179
明確にするために、最初のコマンドは真の「元に戻す」です。HEAD、作業ディレクトリ(変更なし)、およびの前のインデックス状態を生成しgit commit --amendます。2番目は、新しいコミットへの「やり直し」です。これらはgit commit、単に機能するだけでなく、すべての機能を果たします--amend
cdunn2001

60
したがって、サルベージする必要がある新しいコミットメッセージで修正しなかった場合、2番目の部分は通常のにすることができgit commitます。
Matt Montag、2012年

18
何らかの理由で、実行中にエラーが発生しましたgit reset --soft HEAD@{1}fatal: ambiguous argument 'HEAD@1': unknown revision or path not in the working tree. Use '--' to separate paths from revisions。(JJDに感謝!)にHEAD@{1}示されている同等のコミットハッシュに置き換えたところgit reflog、この答えはすばらしいものでした
Tim Camber、2012

20
@TimArnoldは、シェルによっては、一重引用符または二重引用符を囲む必要がある場合がありますHEAD@{1}echo HEAD@{1}たとえばtcshで実行すると、出力はHEAD@1中括弧がtcshによって解釈されたためです。単一引用符を使用すると、中括弧が保持されます。
ケルビン

136

ref-logを使用します

git branch fixing-things HEAD@{1}
git reset fixing-things

次に、以前に修正したすべての変更を作業コピーにのみ入れ、再度コミットできます

以前のインデックスタイプの完全なリストを表示するには git reflog


7
これもインデックスをワイプします-まだ便利ですが、単純な「元に戻す」だけではありません。
cdunn2001

3
との間に違いはHEAD@{1}ありHEAD~1ますか?
neaumusic 2015

15
@neaumusic:はい!現在のコミットのHEAD~1まったく同じでHEAD^、識別子です。一方、これはHEADがこのコミットの前に指し示したコミットを指します。つまり、別のブランチをチェックアウトしたり、コミットを修正したりすると、別のコミットを意味します。HEAD@{1}
knittl 2015

@knittlああ、これが以前は可能だったと思っていなかったのも不思議ではありません。もう一度感謝します。良い情報
neaumusic

9
最初のステップは冗長です。シンプルgit reset HEAD@{1}で十分です。
16

79

修正したコミットを見つけるには:

git log --reflog

注:--patch明確にするために、コミットの本文を表示するために追加できます。と同じgit reflog

次に、以下の方法で問題がなかった時点で、HEADを以前のコミットにリセットします。

git reset SHA1 --hard

注:SHA1を実際のコミットハッシュに置き換えます。また、このコマンドはコミットされていない変更すべて失うため、以前に隠しておくこともできます。または、代わりにを使用--softして最新の変更を保持してからコミットします。

次に、その上に必要な他のコミットをチェリーピックします。

git cherry-pick SHA1

26
その場合git reset SHA1 --soft、最新の変更を保持してコミットできます。
pravj

24

マニュアルからいつでもコミットを分割できます

  • git rebase -i commit ^を使用してインタラクティブなリベースを開始します。ここで、commitは分割するコミットです。実際、そのコミットが含まれている限り、どのコミット範囲でも問題ありません。
  • アクション「編集」を使用して、分割するコミットをマークします。
  • そのコミットの編集に関しては、git reset HEAD ^を実行します。その効果は、HEADが1つ巻き戻され、インデックスがそれに追随することです。ただし、作業ツリーは同じままです。
  • ここで、最初のコミットで使用するインデックスに変更を追加します。これを行うには、git add(おそらく対話式)またはgit-gui(またはその両方)を使用できます。
  • 現在適切なコミットメッセージで現在のインデックスをコミットします。
  • 作業ツリーがきれいになるまで、最後の2つの手順を繰り返します。
  • git rebase --continueを使用してリベースを続行します。

26
複雑すぎる。git reflog必要なのはこれだけです
knittl 2009

2
手順はたくさんありますが、各手順は複雑でなく簡単です。これは私のために働き、私の投票を獲得します。
OzBandit

5
さらに、この回答により、誤って「修正」した変更を選択的に選択して、git reset --soft HEAD @ {1}アプローチに追加の値を提供することができます(これは私の問題BTWを解決しました)
Wiebe Tijsma

2
reflogメソッドでも変更を選択して選択できます。ただ、やるgit reset代わりにgit reset --soft行い、その後、git add --patch
geekofalltrades 2015年

1
これはまだ履歴を書き換え、強制プッシュを必要とします。問題となるかどうかは、状況によって異なります。
Pajn


14

おそらくgit reflog、修正前と修正後の2つのコミットを取得するために使用できます。

次にgit diff before_commit_id after_commit_id > d.diff、修正前と修正後の差分を取得するために使用します。

次にgit checkout before_commit_idコミットする前に戻るために使用します

そして、最後に使用git apply d.diffした実際の変更を適用します。

これで問題は解決しました。


11

コミットをリモートにプッシュし、そのコミットへの変更を誤って修正した場合、これで問題が解決します。git logコミットの前にSHAを見つけるためにa を発行します。(これは、リモートがoriginという名前であると想定しています)。次に、そのSHAを使用してこれらのコマンドを発行します。

git reset --soft <SHA BEFORE THE AMMEND>
#you now see all the changes in the commit and the amend undone

#save ALL the changes to the stash
git stash

git pull origin <your-branch> --ff-only
#if you issue git log you can see that you have the commit you didn't want to amend

git stash pop
#git status reveals only the changes you incorrectly amended

#now you can create your new unamended commit

3
これはより一般的な質問の特別なケースですが、私の緊急のニーズを正確にカバーしました。
dmckee ---元モデレーターの子猫

8

あなたはあなたの元に戻すために以下を行うことができます git commit —amend

  1. git reset --soft HEAD^
  2. git checkout files_from_old_commit_on_branch
  3. git pull origin your_branch_name

====================================

これで、変更は以前と同じです。これで、元に戻す操作が完了しましたgit commit —amend

これでgit push origin <your_branch_name>、ブランチにプッシュすることができます。


3

これまでほぼ9年遅れましたが、このバリエーションが同じことを達成することについて言及されていませんでした(これは、これらのいくつかの組み合わせのようなもので、トップアンサー(https://stackoverflow.com/a/1459264/4642530)に似ています) 。

ブランチ上のすべての切り離されたヘッドを検索します

git reflog show origin/BRANCH_NAME --date=relative

次に、SHA1ハッシュを見つけます

古いSHA1にリセット

git reset --hard SHA1

次に、押し上げます。

git push origin BRANCH_NAME

できました。

これにより、以前のコミットに完全に戻ります。

(以前に上書きされたデタッチされたコミットヘッドの日付を含む)


はい。ただし、通常--softは変更を保持するためにリセットしたいと思います。私はそれを個別にコミットしたいだけです
Juan Mendes

2
  1. 最後のコミットで一時ブランチにチェックアウト

    git branch temp HEAD@{1}

  2. 最後のコミットをリセット

    git reset temp

  3. これで、すべてのファイルが以前のコミットと同様にコミットされます。すべてのファイルのステータスを確認します。

    git status

  4. gitステージからコミットファイルをリセットします。

    git reset myfile1.js (など)

  5. このコミットを再アタッチ

    git commit -C HEAD@{1}

  6. ファイルを追加して新しいコミットにコミットします。

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