web-dev-qa-db-ja.com

Git commitを削除しても変更を保存することはできますか

私の開発部門の1つでは、コードベースにいくつかの変更を加えました。私が取り組んでいた機能を完成させることができる前に、私は現在のブランチをmasterに切り替えていくつかの機能をデモしなければなりませんでした。しかし、単に "git checkout master"を使っても私の開発ブランチで行った変更は保存されているので、masterの機能のいくつかは壊れています。だから私は自分の開発ブランチでコミットメッセージ "temporary commit"を使って変更をコミットしてからデモのマスターをチェックアウトしました。

デモを終了して開発ブランチの作業に戻ったので、行った変更を保持しながら、行った「一時的なコミット」を削除します。それは可能ですか?

748
tanookiben

それはこれと同じくらい簡単です:

git reset HEAD^

git resetまたは--hardのない--softは、ファイルを変更することなく、指定されたコミットを指すようにHEADを移動します。 HEAD^は現在のコミットの(最初の)親コミットを指します。これはあなたの場合は一時的なコミットの前のコミットです。

別の選択肢として、通常どおりに続行してから、次のコミットポイントで代わりに実行することができます。

git commit --amend [-m … etc]

代わりに 編集 /最新のコミットが行われ、上記と同じ効果があります。

他の誰かがそれを引っ張ってきた場所に悪いコミットをすでに押し付けている場合、これは(ほとんどすべてのgit回答と同様に)問題を引き起こす可能性があることに注意してください。それを避けよう

1189
Gareth

これを処理する方法は2つあります。どちらが簡単かはあなたの状況によります

リセット

取り除きたいコミットが最後のコミットであり、追加の作業を何もしていない場合は、単にgit-resetを使用できます。

git reset HEAD^

現在のHEADの直前にあるブランチをコミットに戻します。ただし、実際には作業ツリーのファイルは変更されません。その結果、そのコミットにあった変更は修正されたものとして現れます - それは 'uncommit'コマンドのようなものです。実際には、それを行うためのエイリアスがあります。

git config --global alias.uncommit 'reset HEAD^'

そうすれば、将来git uncommitを使って1つのコミットをバックアップすることができます。

スカッシュ

コミットを潰すとは、2つ以上のコミットを1つにまとめることを意味します。私はこれをかなり頻繁にします。あなたのケースでは、半分完了した機能がコミットされています、そして、あなたはそれを終えてそして適切な、永久のコミットメッセージで再びコミットするでしょう。

git rebase -i <ref>

これはコミットがいくつでも戻ってくる可能性があることを明確にしたいためです。 git logを実行して取り除きたいコミットを見つけ、そのSHA1をコピーして<ref>の代わりに使用します。 Gitは対話式リベースモードにあなたを連れて行きます。現在の状態と<ref>の代わりに行ったものとの間のすべてのコミットが表示されます。したがって、<ref>が10コミット前の場合、10コミットすべてが表示されます。

各コミットの前に、それはWord pickを持ちます。取り除きたいコミットを見つけて、それをpickからfixupまたはsquashに変更します。 fixupを使用すると、そのコミットメッセージを破棄し、変更内容をリスト内の直前のものにマージします。 squashキーワードでも同じことができますが、新しく組み合わせたコミットのコミットメッセージを編集できます。

エディタを終了すると、コミットはリストに表示されている順序でコミットされます。そのため、一時的なコミットを行い、その後同じブランチで他の作業を行い、後のコミットで機能を完了した場合は、rebaseを使用してコミットを再ソートしてそれらをスカッシュすることができます。

警告:

履歴を変更することでリベース - あなたが他の開発者とすでに共有したことのあるコミットに対してこれを行わないでください。

隠し場所

将来的には、この問題を回避するために、コミットされていない作業を一時的に保管するためにgit stashを使用することを検討してください。

git stash save 'some message'

これはあなたの隠しリストの横にあなたの現在の変更を保存します。上記はstashコマンドの最も明示的なバージョンです。あなたが何を隠しているのかを説明するコメントを入れることができます。 git stashを実行するだけで他には何もできませんが、メッセージは保存されません。

あなたはあなたの隠し場所リストを閲覧することができます...

git stash list

これはあなたのすべての隠し場所、それらが行われた枝、そして各行の先頭とメッセージ、そしてstash@{#}のような識別子を表します。

Stashを元に戻すには(stashが最初に作成された場所に関係なく、どのブランチでも実行できます)、単に実行するだけです。

git stash apply stash@{#}

繰り返しますが、#はstashの配列内の位置です。復元したい隠し場所が0の位置にある場合、つまりそれが最新の隠し場所である場合。そうすれば、スタッシュ位置を指定せずにコマンドを実行することができます。gitは、最後の位置を意味するものと想定します:git stash apply

したがって、たとえば、自分が間違ったブランチに取り組んでいることに気付いた場合、次のような一連のコマンドを実行します。

git stash
git checkout <correct_branch>
git stash apply

あなたの場合は、もう少し枝を移動しましたが、それでも同じ考え方が当てはまります。

お役に立てれば。

150
eddiemoya

私はあなたがこれを探していると思います

git reset --soft HEAD~1

そのコミットで行われた変更をステージングに維持しながら、最新のコミットを取り消します。

46
Sudhanshu Jain

はい、変更を削除せずにコミットを削除できます。git reset @〜

32

Zshを使っている人は、次のようにしなければなりません。

git reset --soft HEAD\^

ここで説明しました: https://github.com/robbyrussell/oh-my-zsh/issues/449

URLが無効になった場合、重要な部分は次のとおりです。

あなたのコマンドで^をエスケープする

毎回それをエスケープする必要がないようにあなたは代わりにHEAD〜を使うことができます。

8
Greg Hilston

私の場合、私はすでにレポにプッシュしました。痛い!

次のようにすれば、ローカルファイルの変更を維持しながら特定のコミットを元に戻すことができます。

git revert -n <sha>

このようにして私は私が必要とした変更を保存し、すでにプッシュされたコミットを取り消すことができました。

6
Wim Feijen

Git 2.9(正確には2.9.2.windows.1)を使うとgit reset HEAD^はもっと多くのことを促します。ここで何が期待されるのかわからない。以下のスクリーンショットを参照してください

enter image description here

変更をそのままにしてリセットしたいローカルコミットの数を選択することができる他の解決策git reset HEAD~#numberOfCommitsを見つけました。そのため、限られた数のローカルコミットだけでなく、すべてのローカルコミットも破棄することができます。

git reset HEAD~1の動作を示すスクリーンショットを以下に参照してください。 enter image description here

enter image description here

3
nkharche

もう1つの方法があります。

一時コミットの先頭にコミットを追加してから、次のようにします。

git rebase -i

2つのコミットを1つにマージするには(コマンドでテキストファイルを開いて編集します)。

2
Ruslan Osipov

あなたはgit reset HEAD^ --softgit reset HEAD^ --mixedを探しています。

docs に記載されているように、resetコマンドには3つのモードがあります。

git reset HEAD^ --soft

git commitを元に戻します。作業ツリー(プロジェクトフォルダ)+インデックス(--cached)にはまだ変更があります。

git reset HEAD^ --mixed

git commit + git addを元に戻します。作業ツリーにはまだ変更があります

git reset HEAD^ --hard

あなたがコードベースにこれらの変更を加えたことがないように。作業ツリーから変更がなくなりました。

0
Bar Horing