Git 時空操作のススメ

# 投稿目的
<ul>
<li>現場での対応の備忘録 兼 Git初心者への情報共有</li>
<li>「ふわっとした理解」を「ぷにっとした理解」くらいに固める</li>
<li>有識者からご指摘をいただく</li>
</ul>



# 本記事について
現場に配属されてからというもの、Gitを用いて`時空操作`することがたびたびありました (Gitでやらかした際に対処する経験を積ませていただきました)。
その時の備忘録 兼 Git初心者の方への知識共有として、本記事を執筆します。
※VSCode & Git Graphを使用しています。



# 事例紹介「コミットメッセージを間違えた...」
あっ...コミットメッセージに日付を入れるの忘れてpushしてた...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/2d722b0a-c0e8-733f-0e90-db7ed47e6d56.png)

>上記`2023/11/20`ブランチ(ピンクのブランチ)のコミットメッセージについて、
><ul>
><li>正 : [日付] コミット内容</li>
><li>誤 : コミット内容(今の内容)</li>
></ul>
<br />


### 解決策① `git commit --amend`コマンドを使う
最初に「Git コミットメッセージ 変更」でググると先頭に出てくるこのコマンド。__直前のコミットを変更__ できるみたいですね。
いったんターミナルで`git commit --amend`を実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/87a12d60-2886-017e-c884-79b39f8289bc.png)
何やら仰々しい画面が出てきました...
これは「<a href="https://ja.wikipedia.org/wiki/Vim">Vim(Wikipedia)</a>」というテキストエディタです。
`ログインページ タイトルとテスト修正`を編集して、「2023/11/20 ログインページ タイトル文言とテスト修正」に書き換えます。
しかし、`back spaceが効かない、、だと、、、`という状況になってしまいます。Vimエディタの仕様ですね。

私の場合、
<ul>
<li>Vimエディタ特有の操作知識が求められる</li>
<li>「<a href="https://ja.wikipedia.org/wiki/Vi">Vi(Wikipedia)</a>」ちゃんを愛している</li>
<li>直前のコミットしかコメントを変えられない</li>
</ul>

ため`git commit --amend`兄貴とは疎遠です。`:q`でさよならします...
<br />

### 解決策② コミット内容の退避→取り込みを繰り返す
###### (1)`git reset --soft HEAD^`
このコマンドは、**先頭のコミットを取り消して、ファイルをステージングした状態に戻す**コマンドです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/02c58458-96ef-1143-a8d2-41c5172661fe.png)
この状態で`git reset --soft HEAD^`してみると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/e78dcf63-bc52-41ad-95b9-a7ffaebadc0d.png)
**コミットが取り消された && 変更したファイルがステージング**されています。

###### (2)`git stash`
このコマンドは、`コミットしていない変更を、いったん退避させる`コマンドです。
(1)の`git reset --soft HEAD^`をした状態で`git stash`してみると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/7f2f071f-a550-955c-44be-5e06e5e77831.png)
緑色の部分に、ステージングされていたファイルがまとめられています。
彼らはコミットされたわけではないのでご安心を。

###### (3) (1)(2)を繰り返す
今回の場合、コミットメッセージを間違えたコミットは3つです。今はまだそのうちの1つにしか到達できていません。
なので、戻したいコミット分だけ(1)(2)を繰り返していきましょう。
全部やった後がこちら。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/f0df1db3-e055-965d-3614-95b766b3e44b.png)

###### (4)`git stash apply 'stash@{[適用したいstashのインデックス]}'`とコミットメッセージ修正
あとは、退避させた変更をコミットメッセージを修正した状態で適用すればOKです。
そのために、`git stash apply 'stash@{0}'`すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/cfb0409c-f81c-6bca-ad4d-4ca14d8c9038.png)
インデックス0の内容が適用されています!
あとはコミットメッセージを修正してステージング、「Commit」ボタンを押下すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/f5710b86-a2f7-96da-8293-c3d38d236025.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/ad73fd50-da96-c362-5fc2-b29306b2ed2b.png)
修正できました! 今回適用したstashはもう使わないので、`git stash drop 'stash@{0}'`で削除しておきましょう～
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/0fe3e569-2c54-81c3-da78-25258325f24d.png)

あとはこの(4)の内容を繰り返していくと...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/67f067e9-d094-768c-6613-fda827feef6a.png)
無事コミットメッセージを修正できました!!

※`stash`のインデックスは、「一番最近`stash`されたものが0」になります。変化しているかもしれないので、`git  stash apply`前にインデックスを確認しましょう。
※現場では`stash@{0}`でstashの適用・削除が可能でしたが、家だと`'stash@{0}'`とシングルクオートが必要でした。
→PowerShellを使っている場合に`{0}`が式だと認識される影響のようですね～ <a href="https://sevenb.jp/wordpress/ura/2018/09/18/gitpowershell%E3%81%A7git-stash-apply-stash0%E3%81%A7unknown-option-encodedcommand%E3%81%A8%E8%A8%80%E3%82%8F%E3%82%8C%E3%82%8B/">※エンジニ屋 TFUMIAKI様 (外部リンク)</a>

###### (5)`git push -f origin [修正後のブランチ名]`
あとはpushすれば`時空操作`完了です!
しかし、この状態で`git push origin 2023/11/20`をすると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/c270c244-60ab-3e0f-3789-7361f71e994e.png)
エラーが発生します...
「君はリモートにいる`2023/11/20`君ではないでしょ」とGitが伝えてくれていますね。
なので、`git push -f origin 2023/11/20 (force push)`すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/3ca5bc87-6530-3c5e-6a62-bebefadafb56.png)
今度はpushできました!!
リモートの方でコミットメッセージを確認します。ばっちりですね!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/bb441ab9-2172-4c55-9a4d-1c7945a61c43.png)
これにて`時空操作`完了です。

※`git push -f`は、今までのコミットを消してしまう可能性があります。ほかの人との共有ブランチなどでは、`git pull origin [ブランチ名]`→`git push origin [ブランチ名]`しましょうね。
※私は先輩のコミットを削除してしまったことがありました...申し訳ございません...
<br />


### 解決策③ ブランチを新しく作る
個人的には解決策③が好きです。
###### (1)ブランチの根元で`git checkout -b [新しいブランチ]`
今回の場合は
1. `git checkout a72ca537dd6f3e7e107caa6f2ba99c090b37ea75`で根元に移動
2. `git checkout -b 2023/11/20_new`で新ブランチ作成 (名前が被っているとNG)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/5c7c63e1-bd43-9c78-5bbf-e22abee9fe42.png)

###### (2) `git cherry-pick [盗みたいコミットのハッシュ値]`
さて、`2023/11/20_new`ブランチに現在います。
このブランチに、`2023/11/20`ブランチの「ログインページ タイトル追加」のコミットを持ってきたいです。
その時に用いるのが`git cherry-pick`コマンド。
ターミナルで、`git cherry-pick aec3178b630c381d2351c206bc97d6c5e5306b54`を実行すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/cd2204ba-59d9-9073-5a65-90585364d944.png)
狙い通り、「ログインページ タイトル追加」のコミットを盗めました！

###### (3) `git reset --soft HEAD^`
盗めたはいいものの、コミットメッセージを更新できていません...
もう一度コメントを追加してコミットするため、`git reset --soft HEAD^`を実行します。
すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/ec75b689-f872-62ff-df36-0d5a70ed64de.png)
ステージング状態に戻せました。
これで、コメントメッセージを更新してコミットすれば**正しいコミットメッセージ && コミット内容**を実現できますね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/f18235bb-3dd4-4431-bb34-152e862720c1.png)
↑「Commit」ボタンを押下すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/7038a2a8-eefd-e0a2-1129-3ef46863339b.png)
コミットメッセージを正しく修正できました！

後は、(1)~(3)を繰り返していきます。
大変ですが、混乱して変なブランチを爆誕させるよりはいいかと...

なお、後から修正はできますが
<ul>
<li>コミットのハッシュ値間違い</li>
<li>コミットメッセージ間違い</li>
</ul>
には注意です！

###### (4)`git branch -m [修正後のブランチ名]`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/76d8917c-9c5b-ff7f-826a-5d1bd8d71406.png)
全てのコミットで、**正しいコミットメッセージ && コミット内容**を実現できました！
あとはブランチの名称を修正しpushすれば完璧です。

>`2023/11/20_new`を`2023/11/20`としてpushしたい

いったん、`2023/11/20`に移動し、ブランチ名を変更しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/845733ef-ce3f-11b5-b203-21bf618669cf.png)
この状態で、`git branch -m 2023/11/20_old`を実行すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/5e35b6f9-f4bd-3c22-12ae-655dd25ae210.png)
ブランチ名が変更されました!
そして、再び`2023/11/20_new`に移動し、`git branch -m 2023/11/20`を実行すると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/980a2d1b-e14f-01ea-480e-204c8de4c382.png)
もともと`2023/11/20_new`であったブランチを`2023/11/20`として扱えるようになりました!!

###### (5)`git push -f origin [修正後のブランチ名]`
解決策②(5)と同じです。ばっちりですね!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519885/bb441ab9-2172-4c55-9a4d-1c7945a61c43.png)



### まとめ
```Git:時空操作時に役立つコマンドたち
// 今いるブランチの先頭のコミットを、git addした状態に戻せるよ
git reset --soft HEAD^

// まだコミットしていない変更を退避できるよ
git stash
// 退避したファイルを適用できるよ
git stash apply 'stash@{[stashのインデックス]}'
// 退避したファイルを削除できるよ
git stash drop 'stash@{[stashのインデックス]}'

// 指定したコミットIDのコミット内容を持ってこれるよ
git cherry-pick [コミットID]

// 今いるブランチの名前を変えられるよ
git branch -m [新しい名称]

// 時空を歪めたブランチをもう一度originにpushできるよ(使い方注意)
git push -f origin [ブランチ名]
```



### 最後に
Git Graph様は最高です。VSCode民の皆様はぜひご活用ください。

間違いやGitに関する武勇伝などございましたら、コメントいただけますと幸いです！

今後は、最近勉強しているNext.js/Reactの内容を中心に執筆しようと思います~