gitでコミットの一部を元に戻す


144

gitの特定のコミットを元に戻したいのですが。残念ながら、私たちの組織はまだCVSを標準として使用しているため、CVSにコミットすると、複数のgitコミットが1つにまとめられます。この場合、元のgit commitを選びたいのですが、それは不可能です。

git add --patchコミットのどの部分を元に戻すかを決定するために差分を選択的に編集できるような同様のアプローチはありますか?


ここでより多くのソリューション、特定のファイルへの部分的な復帰を制限することに焦点を当てています。
ntc2 14

回答:


226

--no-commit-n)オプションを使用しgit revertて変更をステージング解除し、次に使用しますgit add --patch

$ git revert -n $bad_commit    # Revert the commit, but don't commit the changes
$ git reset HEAD .             # Unstage the changes
$ git add --patch .            # Add whatever changes you want
$ git commit                   # Commit those changes

注:git add --patchを使用して追加するファイルは、元に戻したいファイルであり、保持したいファイルではありません。


13
gitにあまり慣れてgit reset --hardいない場合は、コミット後に、元に戻したくない他の変更を破棄するために、最後に必要なコマンドを追加する価値があります。
2012

15
git reset --hard初心者にとっては、編集内容が失われる可能性があるため危険です。代わりにgit status、これはgit checkout -- FILE..、物事をより安全に戻すためのヒントになります。
Tino 2013

何ぽっかり省略でgitgit revertただ--patch引数を取る必要があります。
Kaz 2017年

@Kaz:git revertコミット全体を元に戻すために使用されます。を使用git checkout -pして、戻すビットをインタラクティブに選択できます。
mipadi 2017年

1
私はまた、(おそらく)明白なものを追加したいと思います。これは最初に作業を保存することです。どちらかcommit最初に、またはstash、それからしてみてくださいrevert
フェリペアルバレス

39

私は以下をうまく使いました。

最初に完全なコミットを元に戻します(インデックスに入れます)が、コミットはしません。

git revert -n <sha1>  # -n is short for --no-commit

次に、元に戻されたGOOD変更をインデックスからインタラクティブに削除します

git reset -p          # -p is short for --patch  

次に、悪い変更の逆差分をコミットします

git commit -m "Partially revert <sha1>..."

最後に、元に戻されたGOOD変更(resetコマンドによってステージングが解除された)は、まだ作業ツリーにあります。それらをクリーンアップする必要があります。他にコミットされていない変更が作業ツリーに残っていない場合、これは

git reset --hard

5
これは、reset HEAD .動作するディレクトリの最終的なクリーンアップを必要としないため、受け入れられた回答(を使用)の優れた代替手段ではありませんか?
Steven Lu

2
この回答はreset -p、のreset HEAD後に続くよりも短いため、優れていadd -pます。ただし、リセットされた「正常な」ハンクはコミット後も作業ディレクトリに残っているため、クリーンアップが必要です。
Chiel ten Brinke

必要な変更をインタラクティブに削除すると混乱が生じ、エラーが発生しやすくなるため、この回答は優れていません。特に、編集が必要な場合はそうです。
Kaz 2017年

5

個人的には、自動生成されたコミットメッセージを再利用し、ユーザーが「部分的に」という単語を編集して最後にコミットする前に貼り付ける機会をユーザーに提供するこのバージョンを好みます。

# generate a revert commit
# note the hash printed to console on success
git revert --no-edit <hash to revert>

# undo that commit, but not its changes to the working tree
# (reset index to commit-before-last; that is, one graph entry up from HEAD)
git reset HEAD~1

# interactively add reversions
git add -p

# commit with pre-filled message
git commit -c <hash from revert commit, printed to console after first command>

# reset the rest of the current directory's working tree to match git
# this will reapply the excluded parts of the reversion to the working tree
# you may need to change the paths to be checked out
# be careful not to accidentally overwrite unsaved work
git checkout -- .

4

解決:

git revert --no-commit <commit hash>
git reset -p        # every time choose 'y' if you want keep the change, otherwise choose 'n'
git commit -m "Revert ..."
git checkout -- .   # Don't forget to use it.

それが受け入れられた解決策とどのように異なるかをあなたが言ったならそれは人々を助けるでしょう
CharlesB '

1
@Krzysztof末尾のチェックアウトが重要なのはなぜですか、またこのソリューションがuser1338062のソリューションと異なるのはなぜですか?
火曜日2014

3

(ファイルの現在のバージョンが元に戻そうとしているバージョンからそれほど遠くない場合)もう1つの方法は、部分的に元に戻したい(直前の)コミットのハッシュを取得することですgit log。次に、コマンドは次のようになります。

$ git checkout -p <hash_preceding_commit_to_revert> -- file/you/want/to/fix.ext

これは作業ツリー内のファイルを変更しますが、コミットは作成しません。そのため、本当に詰まっている場合は、からやり直すことができますgit reset --hard -- file/you/want/to/fix.ext


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