LoginSignup
3
5

開発中に間違ってCommit,Push,Mergeした時の対処法[git revertとgit reset(soft mixed hardの違い)]

Last updated at Posted at 2024-05-22

この記事では開発途中にプルリクエストを間違ってマージしてしまった際やmainブランチに直接Pushした際,変更内容を戻す(revert,reset)方法について記載する.

今回の操作は基本的なgit操作を熟知している人が行うべきである.そのため以下の記事の内容を知っていることは前提とする
https://qiita.com/tarakokko3233/items/ad7e1a1a14d3e2f10da3

そもそも...

親ブランチに直接プッシュ,マージする際はプロジェクトマネージャーに相談し,勝手に親ブランチに変更を加えないようにすること

githubではプルリクエストができてマージができないようにするWriter権限がある,admin権限付与は適切な人のみにすること.

git revert git resetとは

事象確認

スクリーンショット 2024-05-22 11.33.37.png

このような作業ツリーの構造だった場合,
1.コミットを取り消したい!
2.細かくコミットしすぎたのでまとめたい!
3.featureブランチから直接mainブランチにマージしてしまった!
4.developmentブランチからmainブランチに間違ったタイミングでマージしてしまった!
5.mainブランチ/developmentブランチに直接プッシュしてしまった!
時に,どのように対処するかについて記載する.

revertとresetの違い

使用シナリオ

git revert
公開されたコミットを取り消す際に使用される.コミット履歴を維持しながら,特定のコミットの変更を元に戻すことができる.

git reset
ローカルでのコミットの取り消しや,ブランチを特定のコミットに戻す際に使用される.通常,公開されていないコミットに対して使用する.

動作の違い

git revert
指定したコミットの変更を取り消すための新しいコミットを作成する.元のコミットは履歴に残り,新しいコミットで変更が打ち消される.

git reset
現在のブランチを指定したコミットまで移動させ,それ以降のコミットを取り消す.コミット履歴が変更され,指定したコミット以降のコミットは削除される.

コミット履歴への影響

git revert
新しいコミットを作成することでコミットを取り消すため,コミット履歴が維持される.取り消したコミットと新しいコミットの両方が履歴に残る.

git reset
指定したコミット以降のコミットを完全に削除するため,コミット履歴が変更される.取り消したコミットはなくなる.

作業ツリーとインデックスへの影響

git revert
作業ツリーとインデックスを更新する.新しいコミットによって,作業ツリーとインデックスが変更される.

git reset
作業ツリーとインデックスを指定したコミットの状態に戻す.--hardオプションを使用すると、作業ツリーとインデックスの変更が失われる.

リモートリポジトリへの影響

git revert
作成された新しいコミットは,通常のgit pushでリモートリポジトリにプッシュできる.他の開発者のリポジトリに影響を与えることはない.

git reset
変更したコミット履歴をリモートリポジトリにプッシュするには,通常はgit push --forceが必要.これにより、他の開発者のリポジトリに影響を与える可能性がある.

一般的に,git revertは,コミット履歴を維持し,他の開発者への影響を最小限に抑えるために推奨される.git resetは,ローカルでのコミットの操作に適している.

git reset を使用する場合は,リモートリポジトリへの影響を考慮し,他の開発者との調整が必要.
git revert を使用する場合は,取り消すコミットを正確に指定し,新しいコミットのメッセージを適切に記述することが重要.

git resetの種類

git resetは3種類のオプションがある.
git reset --soft
git reset --mixed
git reset --hard
である.

resetの種類はこの記事でも説明している
https://qiita.com/bearl27/items/288ead3137bef3670d94

HEADとoriginについて

git resetの種類を知る前に,Gitを触っているとよく見るHEADoriginについて説明する.

スクリーンショット 2024-05-22 20.40.02.png

HEAD
現在作業しているコンテキスト(コミット)で,通常,チェックアウトしたブランチの最新のコミットを表す.

origin
Git で最も一般的に使用されるリモートリポジトリの参照名であり,リモートリポジトリとの間でコードの同期を行う際に使用される.つまりローカルブランチとリモートブランチの区別をするためにリモートブランチにつける名前のこと.

ワーキングエリアとステージングエリアについて

resetの仕組みはワーキングエリアとステージングエリアがおおいに関係している
スクリーンショット 2024-05-22 20.43.16.png

ワーキングエリア
プロジェクトの実際のファイルが存在する場所.ファイルの編集、新規作成、削除などの作業はすべてワーキングディレクトリで行われる.

ステージングエリア
次のコミットに含める変更を準備する場所.つまりローカルブランチに変更するファイルを確認する最終ステージ.

git reset --softとは

git reset --soft  <コミットのハッシュ>

HEADのみが指定したコミットに移動する,ステージングエリアとワーキングエリアの内容は変更されない.つまり指定したコミットにステージングエリアの内容が集約される.これは、現在の変更を保持したまま、新しいコミットを行う,つまりコミット(ファイルの変更履歴)をまとめる時に便利である.
スクリーンショット 2024-05-22 21.40.59.png

git reset --mixedとは

git reset --mixed  <コミットのハッシュ>

このオプションを使用すると,HEAD とステージングエリアが指定したコミットに移動するが,ワーキングエリアは影響を受けない.つまり,ステージングされた変更は取り消されるが,ワーキングエリア内のファイル自体の編集内容はそのまま残る.コミットを取り消し,git addするファイルを変更する際に便利である.
スクリーンショット 2024-05-22 21.48.57.png

git reset --hardとは

git reset --hard  <コミットのハッシュ>

HEAD,インデックス,そしてワーキングディレクトリがすべて指定したコミットの状態に完全にリセットされる.これにより,現在のブランチ上のすべてのローカル変更(ステージングおよび未ステージングの変更)が失われる.変更履歴をなくし,現在作業しているファイルを特定のコミットの状態に戻したい時に便利である.

スクリーンショット 2024-05-23 21.42.50.png

実際の事例からどう対処するのか

ここからは実際に起こりうる例に基づいてどのように対処するかの例を記載する.

直前のコミットを取り消したい

リモートブランチのコミットを取り消す場合ではなくローカルブランチの直前のコミットを取り消す

git reset --mixed HEAD^

これでローカルブランチの最新のコミットが解除されるのでコミットし直してプッシュすればリモートに反映される.(mainブランチだった場合)

git push -f origin/main

mainブランチで細かくコミットしすぎたので1つのコミットにまとめたい

これをすることで複数のコミットが一つにまとめられる

mainブランチをチェックアウト

git checkout main

まとめる先のコミットのハッシュを確認

git log

まとめる先のコミットのハッシュをメモして,以下のコマンドを実行する.

git reset --soft <まとめる先のコミットのハッシュ>

この後コミットメッセージを入力するためのエディタが出てくるので1行目にコメントを入力する.
このエディタを保存して閉じればコミットできる.

エディタを保存して閉じる方法(デフォルトのVimなら Esc:wqと入力)

mainブランチ(ローカルブランチ)の変更をorigin/mainブランチ(リモートブランチ)にプッシュする.

git push -f origin main

この操作はgit rebase, git squashを使うと操作しやすい.以下の記事を参考にすること.
[鋭意製作中]

間違えたコミットを残して変更内容を戻したい

これをすることで変更したコミットを残しつつ取り消すことができる(mainブランチを例にする)

mainブランチをチェックアウト

git checkout main

取り消したいコミットの1つ前のコミットのハッシュを確認

git log

取り消したいコミットのハッシュをメモして,以下のコマンドを実行する.

git revert <取り消したいコミットのハッシュ>

この後コミットメッセージを入力するためのエディタが出てくるので1行目にコメントを入力する.
このエディタを保存して閉じればコミットできる.

エディタを保存して閉じる方法(デフォルトのVimなら Esc:wqと入力)

mainブランチ(ローカルブランチ)の変更をorigin/mainブランチ(リモートブランチ)にプッシュする.

git push -f origin main

ある地点までのすべてのコミットを削除して変更内容を戻したい

これをすると指定したコミットより後のコミットが全て削除される.
リモートブランチにプッシュする際は履歴が変更されるため,他の開発者は自分のローカルリポジトリを更新する必要がある.
(mainブランチを例にする)

mainブランチをチェックアウト

git checkout main

取り消したいコミットの1つ前のコミットのハッシュを確認

git log

取り消したいコミットの1つ前のコミットのハッシュをメモして,以下のコマンドを実行し,メモしたコミットまでmainブランチをリセットする.

git reset --hard <コミットのハッシュ>

mainブランチ(ローカルブランチ)の変更をorigin/mainブランチ(リモートブランチ)にフォースプッシュする.

git push -f origin main

これでコンフリクトを無視してプッシュできる

featureブランチから間違ってmainブランチにマージしてしまった時やdevelopmentから間違ったタイミングでマージした時も同様の処理をする.

developmentブランチの内容をmainブランチに強制的に上書きしたい

これをするとmainブランチの現在の内容が完全に失われるので注意.

developmentブランチをチェックアウト

git checkout development

origin/developmentブランチ(リモートブランチ)から最新の状態をdevelopmentブランチ(ローカルブランチ)に同期する.

git pull origin development

mainブランチをチェックアウト

git checkout main

origin/mainブランチ(リモートブランチ)から最新の状態をmainブランチ(ローカルブランチ)に同期する.

git pull origin main

mainブランチの内容を破棄して,developmentブランチの内容で上書きする.

git reset --hard development

mainブランチ(ローカルブランチ)の変更をorigin/mainブランチ(リモートブランチ)にフォースプッシュする.

git push -f origin main

これで完了

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5