ちょっとわかった！Git

# はじめに
Git に関してわかっているつもりで色々と抜けている部分があったので、あらためて学習してみた結果をまとめる。

# Git 初期設定

git アップデート
```tcl:ターミナル
git update-git-for-windows
git --version
```
git 初期設定
```tcl:ターミナル
# email 設定
git config --global user.email "sawa@sawa.com"
# Git で使用するデフォルトのテキストエディタを Visual Studio Code に設定
git config --global core.editor "code --wait"
# 一覧
git config --global -e

# 自分の例
[user]
	email = email@email.com
	name = name
[init]
	default = branch
	defaultBranch = main
[diff]
	tool = vscode
[difftool "vscode"]
	cmd = "code --wait --diff $LOCAL $REMOTE"
[core]
	autocrlf = input
	editor = code --wait
[grep]
	lineNumber = true
```
:::note info
**[difftool "vscode"] に関して**
あとで diff コマンドが出てくるのだが、この設定があると diff を使うとき diff と同じように difftool も使えるようになる。
:::

# Git 基本理解

<dl>
  <dt>０. git 管理なしの状態</dt>
  <dd>↓　git init あるいは git clone [GitHubのURL]</dd>
  <dt>1. ローカル環境</dt>
  <dd>↓　git add .</dd>
  <dt>2. ステージング環境</dt>
  <dd>↓　git commit -m "<メッセージ>"</dd>
  <dt>3. コミット環境</dt>
  <dd>↓　git push origin <ブランチ名></dd>
  <dt>4. リモート環境</dt>
  <dd>↓　git pull origin <ブランチ名></dd>
  <dt>1. ローカル環境</dt>
</dl>

`git init`：
.git フォルダが作成され git 管理が始まる。.git フォルダを削除すると git 管理をリセットできる。このとき空のフォルダは git 管理に認識されないようである。
`git clone <GitHubのURL>`：
GitHub のリポジトリをローカルにクローンしてくるコマンド。リポジトリと一緒に git 管理もクローンしてくる。
`git add .`：
ローカル環境からステージング環境に移動（コミット待ち状態になる）。. (ドット) の代わりにファイル名を指定して add もできる。
`git commit -m "<メッセージ>"`：
ステージング環境からコミット環境に移動（コミット完了状態になる）。
`git push origin <ブランチ名>`：
コミット環境からリモート環境に移動（GitHub**に**ローカルの変更が反映される）。
`git pull origin <ブランチ名>`：
リモート環境の変更をローカルに反映（GitHub**の**変更がローカルに反映される）。

:::note info
**commit に関して**
未 commit 状態でブランチを移動しない方がいい。移動先ブランチが移動元の変更内容で上書きされてしまうことがある。
:::
:::note alert
**push / pull に関して**
ローカルのブランチ名とリモートのブランチ名が一致していることを確認する。ローカルのブランチAからリモートのブランチBに push などはNG。
:::

# Git よく使うコマンド
#### git 状態確認系（オプションは無くてもいい）
```tcl:ターミナル
# コミットしたかしていないか
git status -s
# コミット履歴
git log --all --decorate --oneline --graph
# コミット履歴＋それ以外の更に詳しい履歴
git reflog
# git 管理中のファイル一覧
git ls-files
# そのコミット時に変更した部分
git show <コミットID>
```
#### ブランチ間系
- ブランチの 作成 / 移動 / 削除
```tcl:ターミナル
# 作成
git branch <ブランチ名>
# 移動
git switch <ブランチ名>
# 削除
git branch -d <ブランチ名>
```
- ブランチのマージ
```tcl:ターミナル
git merge -m "<メッセージ>" <ブランチ名>

# コンフリクトしてしまったら？
# コンフリクトしているファイルを訂正し、add と commit をする
git add <ファイル名>
git commit -m "<メッセージ>"

# コンフリクトしてしまって途中でやめたいときは
git merge --abort
```
:::note info
**マージに関して**
ブランチ A の変更をブランチ B（ブランチ A からの派生）に反映できるコマンド。
例えばブランチ B にいるときは git merge -m "<メッセージ>" <ブランチA>。
:::
:::note info
**コンフリクトに関して**
マージするとブランチ同士の変更が競合することもある。
コンフリクトが起きるのは、**マージする２つのブランチがそれぞれ別々に同じファイルを編集して commit** したとき。
たとえば main ブランチに example.txt があるとする。main から切った test ブランチが example.txt に「Good morning」と書いて commit。一方そのとき main では「Good evening」と書いて commit。
これでマージすると、git はどちらの変更が正しいのかわからずコンフリクトが起きる。
:::

# Git 時々使うコマンド
```tcl:ターミナル
# rm 系

# ファイルをステージング環境からローカル環境に移動（未 add 状態にする）
git rm --cached <ファイル名>
# ファイルをステージングからもローカルからも消す
git rm <ファイル名>
```
```tcl:ターミナル
# mv 系

# AからBに名前変更 & 変更を add
git mv <ファイル名A> <ファイル名B>
```
```tcl:ターミナル
# restore 系

# 変更 / 削除をステージング環境からローカル環境に移動（未 add 状態にする）
git restore --staged .
# 変更 / 削除をステージングからもローカルからも消す
git restore .
```
```tcl:ターミナル
# checkout 系

# 過去の特定のコミット時の様子を見に行く
git checkout <コミットID>
# 現在に戻る
git checkout <ブランチ名>
```
```tcl:ターミナル
# stash 系

# 今やっている作業を一時退避
git stash
# メッセージ付き退避
git stash push -m "<メッセージ>"
# 退避中の作業一覧
git stash list
# 退避した作業の復元
git stash apply stash@{<番号>}
# 退避した作業を削除
git stash drop stash@{<番号>}
```
:::note info
**stash に関して**
「commit に関して」で書いたように、commit せずにブランチ移動はしない方がいい。そのため stash で作業をいったん退避してからブランチ移動をするようにする。戻ったときに作業を復元できる。
:::

```tcl:ターミナル
# diff 系 変更の差分を確認

# ローカル環境と直前コミットとの差分
git diff
# ステージング環境と直前コミットとの差分
git diff --staged
# コミット間の差分
git diff <コミットID>..<コミットID>
# ブランチ間の差分
git diff <ブランチ名>..<ブランチ名>

git fetch origin
# ローカルとリモートの差分
git diff HEAD..origin/master
# リモートとローカルの差分
git diff origin/master..HEAD
```

# Git あまり使わないコマンド
```tcl:ターミナル
# revert と cherry-pick

# 特定のコミットで加えた変更を消す
git revert <コミットID>
# 特定のコミットで加えた変更を取り入れる（revert の逆）
git cherry-pick (-n) <コミットID>
```
```tcl:ターミナル
# reset 系

# 戻りたい場所のコミットIDを確認
git reflog
# そのコミット時の状態に戻る
git reset --hard <コミットID>

# オプションに関して
--soft：　指定の状態に戻り、そのとき編集中だったことは commit だけ行っていない状態になる
--mixed：　指定の状態に戻り、そのとき編集中だったことは add だけ行っていない状態になる
--hard：　指定の状態に戻り、そのとき編集中だったことは消える
```
```tcl:ターミナル
# その他

# 文字列検索　VSCodeが使えない環境で活躍
git grep "<文字列>"
# 特定のコミット時のファイルで文字列検索
git grep "<文字列>" <コミットID>

# ファイルの更新履歴を確認
git blame <ファイル名>
```

# Git よくわからないコマンド
```tcl:ターミナル
# rebase 系
# 他のブランチのコミット記録を取り込む？（以下参考画像）
# でも main で rebase してはいけないとも聞くので、使わない方が無難そう
```
![Screenshot (232).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3047950/2ac873f2-0048-ac47-97dd-4bbf38dc01ae.png)


# 関連：Git よく使うファイル
<table>
  <thead>
    <tr>
      <th>ファイル名</th> <th>内容</th>
    </tr>
  </thead>
    <tr>
      <td> .gitignore </td> <td>git 管理しないファイルを指定する（.envなど）。</td>
    </tr>
  <tr>
    <td> .git </td> <td>消すと git 管理がリセットされてしまうので触らない。</td>
  </tr>
</table>

:::note info
**.gitignore に関して**
add されたことがないファイル（git 未管理）は .gitignore できる。add 済みファイル（git 管理中）は先に管理を外す。
:::
:::note info
**.gitignore に関して２**
[gitignore generator](https://www.toptal.com/developers/gitignore) でいろいろな言語やフレームワークの .gitignore サンプルが提供されている。
:::

# 関連：GitHub に関して
- 自分が新しくリポジトリを作る場合の初回 push のやり方
画像に２つコードブロックがあり、ローカルで何も git 管理をしていない場合は上のコードブロックを、ローカルで git init 済みなら下のコードブロックを実行する。
![Screenshot (233).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3047950/1daefbdc-6c28-e971-623b-003daf372069.png)
２回目以降は git push origin <ブランチ名> で push できるのだが、初回は git push **-u** origin mainになっている。**-u = --set-upstream** らしい。

- プルリクの使い方
１．プルリク作成
![Screenshot (237).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3047950/3aa16bc6-5065-f3e0-58b5-2390dab809ed.png)
２．そのブランチがどういう意図で作られて、どういう変更を加えたのか、他の人が読んでわかるように書く。（ブランチ名確認！）
![Screenshot (235).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3047950/70a09ee0-0eab-4006-f167-381aad77e2fc.png)
３．変更にフィードバックをもらい、問題なければマージ。フィードバックで問題を見つけてもらった場合は、ローカルから訂正して push する。
![Screenshot (236).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3047950/9cc504fc-d4f6-9a86-fd85-e1ab11eae82c.png)

# おわりに
学習を経て、少し自信を持って Git を使えるようになったと思う。これからもわからない動作が出てきたときは自分で調べるようにしたい。あと Git の SSH クローンについてもやり方を再確認したい。
Git の学習を勧めてくださったインターン先の上司 I さんに感謝申し上げます。

> 参考にさせていただいた記事
> - [【連載】マンガでわかるGit ～コマンド編～](https://www.r-staffing.co.jp/engineer/entry/20190621_1)
> - [Learn Git – Full Course for Beginners](https://www.youtube.com/watch?v=zTjRZNkhiEU)
> - [Git Tutorial for Beginners: Learn Git in 1 Hour](https://www.youtube.com/watch?time_continue=1&v=8JJ101D3knE&embeds_referring_euri=https%3A%2F%2Fwww.bing.com%2F&embeds_referring_origin=https%3A%2F%2Fwww.bing.com&source_ve_path=Mjg2NjY)
> - [Git and GitHub Tutorial for Beginners](https://www.youtube.com/watch?v=tRZGeaHPoaw)
> - [Git and GitHub Crash Course For Beginners | Complete Tutorial [2024]](https://www.youtube.com/watch?v=l2yrJtwoC_E)