ゆるおたノート

Tomorrow is another day.

【Git勉強中】あっ!そのコミット訂正させてください!

うっかりなあなたに。そう、つまり私。

はじめに

基本の流れ

www.yuru-wota.com

凡例

記号・用語 意味 使い方
$ 「"コマンドライン"で使えるコマンド」のしるし。 通常、Gitを始めとする「シェルスクリプト」系の説明では、コマンドの文頭に$をつけて表現されることが多いようです。
当ブログでもそれに倣って記載してます。
実際にコマンドを入力するときは、git~以下をコピペしてください。
# コメント 補足事項など。
(対話モードでは使えません、、、)
<> 編集点(という表現で良いのかな…?) 任意の名前、識別子を入力してください。
(コミットの)識別子 コミットごとにつく半角英数字7桁の番号。 SHA-1というハッシュ値らしいです。
当記事では<コミット>のことを指します。

コミットの取り消し

直前のコミットを取り消す

ブランチのコミット履歴のみ書き換え

git addしているインデックスと、作業ツリーはそのままにします。

$ git reset --soft <ブランチ名>
【例】
$ git reset --soft HEAD^
ブランチのコミット履歴とインデックスを書き換え(デフォルト)

作業ツリーのみ残ります。

$ git reset --mixed <ブランチ名>

なお、git resetmixedモードがデフォルトなので、↑のコマンドは下記のようにも書けます。

$ git reset <ブランチ名>
作業ツリーも含めてすべて書き換え

一つ前のコミット履歴を作成した直後の状態に完全に巻き戻します。
(それまでの変更も含めて)何もなかった状態になります。

$ git reset --hard <ブランチ名>

git reset --hard は、ブランチの歴史を強制的に書き換えてしまう強力なコマンドです。
もしマージコミットをpushしてないのであれば、強気で使ってしまってよいでしょう。
~中略~
もし保存していない変更が作業ツリーやインデックスにあれば、消し飛びますので、実行前にgit statusでなにか作業が残っていないか確認してみて下さい。
- git merge の取り消し方法。reset と revert コマンドについて。 | WWWクリエイターズ

複数のコミットをまとめて取り消し

引数に<ブランチ名>ではなく<コミット>を指定すると、(現在のブランチの)特定のコミットの状態に戻すことが出来ます。

$ git reset --hard <コミット>

間違えたコミットの打ち消し用のコミットを作成

新しくコミットを作成するのでブランチの過去履歴には影響を与えずに済み、pushのコンフリクトを防止します。

$ git revert
$ git revert <ブランチ名>

なお、mergeのコミットを打ち消す時は、注意が必要のようです。
(ここ↓はまだ詳細読んでない…あとで読みます…たぶん…) www-creators.com

コミットメッセージはそのままにする場合

オプションとして--no-editを付加。

$ git revert --no-edit <コミット>

「取り消し」の取り消し

「打ち消しコミット」も含めた履歴の参照

git reflogで、HEADを含めたこれまでのコミット履歴(=「参照」の移動遍歴)を確認できます。
「reflog」は「refer to log」の略ですかね…?

# 入力
$ git reflog

# 結果
3e7182e (HEAD -> develop, master) HEAD@{0}: checkout: moving from master to develop
3e7182e (HEAD -> develop, master) HEAD@{1}: commit: fix directory description and change heading positions.
ba3303d HEAD@{2}: commit: fix the css property table.
c14f55a (origin/master, origin/HEAD) HEAD@{3}: commit: add Table of Contents.
3ef84f7 HEAD@{4}: checkout: moving from master to master
3ef84f7 HEAD@{5}: commit: re-edit directories.
6d75462 HEAD@{6}: commit: change indent from tabs to spaces.
909e2a9 HEAD@{7}: commit: edit filename.
df8920d HEAD@{8}: commit (merge): move to several directories.
d616027 HEAD@{9}: clone: from https://github.com/yuricks7/xxxxxxxx

[識別子] [HEADから●番目]: [アクション]: [コメントorアクションの内容]

指定のコミットに巻き戻す

git resetにブランチ名ではなくHEADの番号を指定すると、「●個前のHEADの状態」に戻すことが出来ます。

$ git reset --hard HEAD@{●●}
【例】
# 入力
$ git reflog

# 結果
3e7182e (HEAD -> develop, master) HEAD@{0}: checkout: moving from master to develop
3e7182e (HEAD -> develop, master) HEAD@{1}: commit: fix directory description and change heading positions.
ba3303d HEAD@{2}: commit: fix the css property table.
c14f55a (origin/master, origin/HEAD) HEAD@{3}: commit: add Table of Contents.
3ef84f7 HEAD@{4}: checkout: moving from master to master
3ef84f7 HEAD@{5}: commit: re-edit directories.
6d75462 HEAD@{6}: commit: change indent from tabs to spaces.
909e2a9 HEAD@{7}: commit: edit filename.
df8920d HEAD@{8}: commit (merge): move to several directories.
d616027 HEAD@{9}: clone: from https://github.com/yuricks7/xxxxxxxx

# HEAD@{5}の時点に強制巻き戻し
$ git reset --hard HEAD@{5}

コミットの修正

直前のコミットを修正して上書き

直前の変更を破棄して、新しいコミットが作成されます。
コミットの識別子も変更されることに注意!

$ git commit -a
$ git commit --amend
「push済みのコミット」とのコンフリクトに注意!

push済みの場合、新しいコミットと(リモート側にある)古いコミット履歴とでコンフリクトが発生してしまう模様…詳細は未確認です…)

コミットをまとめる

現在のブランチで、それまでのコミットを<コミット>まで1つにまとめます。

$ git rebase -i <コミット>
$ git rebase --interactive <コミット>

詳しい手順の解説はこちらの記事におまかせ。

「push先リポジトリ内の履歴」とのコンフリクトに注意!

「rebase前の履歴」をすでにリモートにpush済みの場合、「rebase後の履歴」とコンフリクトしてしまいます。
後者の適用で問題なければ、下記のコマンドで強制的にリモート側の履歴を書き換えます。

# 強制的に<ブランチ名>へPushする
$ git push -f origin <ブランチ名>
$ git push --force origin <ブランチ名>
使いどころに注意!

チームで開発しているときなど、複数人が参照しているブランチ(master等)ではさらにコンフリクトが発生する原因になるので使わないこと。

参照