ham-capのブログ

プログラミング学習の記録

【Git】プルリクに関係のない変更が紛れ込んでしまった時の対処法

今回はフィヨルドブートキャンプの課題レビューで指摘され、久しぶりにGitであれこれやってみたことを書きます。

やりたいこと

プルリクエストに不必要な変更が紛れ込んでしまったため、修正してdiffを綺麗にしたい。

前提条件

  1. mainからdevelopブランチを切って作業していた
  2. developブランチでFile_AとFile_Bの修正を行いコミットした
  3. そのコミットをリモートブランチにプッシュし、プルリクエストを作成した
  4. File_Bに対する変更は今回のプルリクには不必要なため、diffに含まないようにとの指摘を受けた

手順

調べてみたところ、こういった場合はリモートブランチそのものを正しい状態にすればプルリクにも反映されるとのことだったので、今回はローカルで修正してリモートブランチを上書きするイメージで進めました。(主にこちらの記事を参考にさせていただきました。)

ケースバイケースで適切なやり方は異なるとは思いますが、今回はgit reset --softを使って過去に戻り、File_Bがコミットに含まれないように修正しました。

何はともあれgit resetで過去に戻ります。

オプションは--softにしましたが、--mixedでも良かったかもしれません。

これらに--hardを加えた3つがgit resetの際に使用する主なオプションです。(本当はもっとたくさんあるっぽいです。)

$ git reset --soft HEAD^

つまり、コミットをする前、ファイルに変更を加えてgit addまでは終わっている状態ということになります。 git statusで状態を確認すると、

$ git status
On branch hogehoge
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   File_A
    modified:   File_B

こんな感じでFile_AとFile_Bがインデックスに追加されているのがわかります。 今回はコミットからFile_Bを除外したいので、インデックスから取り除きます。

$ git restore --staged File_B

もう一度git statusで確認するとインデックスにはFile_Aのみが登録されている状態になるはずです。

あとは普通にコミットすればローカルでの修正は完了です。

コミット後、リモートブランチにプッシュします。

今回の場合は自分しか触らないリポジトリなので、git push --forceで強制的にプッシュしてしまってもいいのですが、いざ複数人で作業をすることになった際に--forceに対して心理的抵抗が全くないのは問題な気がするので、今回はgit push --force-with-leaseを実行しました。

$ git push --force-with-lease

これでコミットの中の余計な変更をプルリクから排除できました。

--forceは取扱注意

今回、ローカルでの修正をリモートに反映させるためにgit push --force-with-leaseを使用しました。

これは自分のローカルリポジトリの履歴と比較して、リモートリポジトリに既に変更が加わっている(他の誰かが先にコミットしている)状況ではプッシュを強制できないようにするオプションで、無条件に--forceでプッシュするよりは他人の努力を水泡に帰する危険性が減ります。

とはいえ、直前にリポジトリ自体をfetchしてきている場合はプッシュできてしまったりするらしいので、絶対安全なものではありません。

いずれにしても、チームで開発するときはそのチームのルールを遵守して適切に対処すべきと思います。

安易に--forceでプッシュとかは絶対アカンやつ。(まだチームで開発したことないけど…)

まとめ

今回は歴史改変のお話でした。 実は最初にgit reset --softを実行する前に--hardで実行してしまい、不必要に巻き戻しすぎたので、git reflogを使ってそのresetを更に無かったことにしたりしてますが、その辺は今回の本筋からはそれてしまうので別記事にまとめたいと思います。

参考

GitHub プルリクエスト後に間違いに気づいたとき

[git reset (--hard/--soft)]ワーキングツリー、インデックス、HEADを使いこなす方法

git push -f をやめて --force-with-lease を使おう