Gitの基礎知識をまとめました

こちらはエンジニアなりたての私が学んだ、Gitの基礎知識になります。
トピックは職場の先輩に大事な部分を抽出いただいてまとめました。
私と同様、初学者さんたちのお力になれれば嬉しいです:blush:


## ローカルリポジトリについて
Gitのローカルリポジトリには３段階がある

#### 1. ワークツリー
自分の作業場所。ここでファイルの作成や編集を行う。
ワークツリーで編集後、`add`していない状態で`git status`を行うと以下のように言われる。
![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269349/bd1e8645-4fbb-b838-a7eb-31b8e8725894.png)
+ Changes not staged for commit→ステージに上がっていない変更があるよ
+ use "git add <file>..." to update what will be committed→addするには`git add <file>`してね
+ use "git restore <file>..." to discard changes in working directory→変更をなかったことにするには`git restore <file>`してね


#### 2. ステージ
ワークツリーで
+ `git add ファイル名`
+ `git add ディレクトリ名`
+ `git add .`　・・・　「．」は全てという意味
 をするとステージという場所にいく。 コミットという場所への準備をする。
 `add`した後、`commit`していない状態で`git status`を行うと以下のように言われる。

 ![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269349/e22702da-d3e9-f004-9a58-6c1c0dd1aaee.png)
+ Changes to be committed　→　コミットされていない変更があるよ
+ use "git restore --staged <file>..." to unstage　→　ステージの変更をなかったことにするには`git restore --staged <file>`してね

#### 3. リポジトリ
ステージで`commit`をするとローカルリポジトリにいく。
ここでスナップショットを記録する。（スナップショットとはある時点のその状態を丸ごと保存したもの）
+ `git commit`・・・エディタ上でコミットメッセージを添えれる。
+ `git commit -m “メッセージ”`・・・エディタを立ち上げずにメッセージを添えれる。
+ `git commit -v`・・・エディタ上でコミットメッセージを添えれる、ファイルの変更内容がエディタ上で見れる。
エディタが立ち上がった後は、⌘S→⌘Qをしてね
ターミナルに戻るとコミットメッセージと共にコミットが成功したことがわかる

![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269349/fdfcf586-3bdd-9d26-409b-2a4dd1295e33.png)
#### この先にGitHub（リモートリポジトリ）がある

## ブランチを作成する方法と削除する方法
#### ブランチとは
分岐して開発する。複数の機能を同時並行で開発できる
    作業完了したら大元のブランチに変更を取り込む。
    ブランチを切る理由は、他のブランチに影響を与えることがないので、複数人が同時並行で作業することができる。また、ブランチごとに履歴が残るので不具合などの修正が容易にできる。
    
#### 作成方法
   + `git branch ブランチ名`・・・ブランチの作成はするけど切り替えはしないよ
   + `git checkout -b ブランチ名`・・・新規ブランチを作成しつつ、切り替えも行うよ　
    
#### 削除
   + `git branch -d ブランチ名`・・・「-d」はdeleteの略。mainブランチに`merge`されていない変更が残っている時は削除しない。
   + `git branch -D ブランチ名`・・・「-D」は強制削除
    
#### 確認方法
+ `git branch`
+ `git branch -a`・・・全てのブランチの表示（リモートブランチも）
`git branch -a`をした時↓
![スクリーンショット 2023-02-21 19.59.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269349/a3ce37e0-2023-c15c-c262-298c837398b0.png)
+ ＊→今自分がいるブランチを指している
+ remotes/origin/feature → 例えば、リモートリポジトリにFeatureブランチがあったとする。
    それを`pull`してくると`remotes/origin/`の中にブランチが入り、このようになる
    

## ファイルに変更を加え、pushするまでの流れ

#### ◎流れ

1. ワークツリーでファイル編集をする
2. `git add`でステージに上げる
3. `git commit`をする
4. `git push リモート名 ブランチ名`コミットした内容をGitHub（リモートリポジトリ）に送る

#### GitHubの新規追加

+ `git remote add origin GitHubのURL`
1. GithubのサイトからRepositries→New→Repository Nameで名前をつける→Create Repositoryでリポジトリを新規作成する

2. 「**…or push an existing repository from the command line**」の１行目をターミナルにコピペするだけでGitHubが生成される！
    

#### ◎豆知識

originという名前でGitHubを登録する。
originがあると今後わざわざURLを打たなくてもGitHubにアップしたり取得したりできる。
GitHubのアクセス先に対してGitがデフォルトでつける名前。もちろんoriginじゃなくてもいいよ。

## ファイルの変更を削除する方法
    
#### ワークツリーの編集作業の取り消し（addする前）
+ `git checkout -- ファイル名`
+ `git checkout -- ディレクトリ名`
+ `git checkout --.`　・・・「．」は全変更を取り消す
”—”をつけるのはブランチ名とファイル名が被った時にGitが分からなくなるのを避けるため。
ターミナル上には何も出ないが、ファイルを見るor`git status`をすると変更が取り消されているのがわかる
    
#### ステージの取り消し
２種類のやり方がある。**reset OR restore**
    
#### reset
+ `git reset HEAD`  ・・・全ファイルの`add`を取り消し
+ `git reset HEAD ファイル名` ・・・指定ファイルの`add`を取り消し
ただし`add`の部分（ステージ）の取り消しなので、 ワークツリーの内容も元に戻したい時は上記の**ワークツリーの編集作業の取り消し（addする前）** をする。
    
#### restore
+ `git restore --staged ファイル名`・・・指定ファイルの`add`を取り消し
+ `--staged`は、指定したファイルをインデックスから削除することができます。
オプションを使用せずに`git restore`のみを実行した場合、ワークツリー内の変更も取り消します。
    
#### コミットの取り消し
+ `git reset --soft コミットID`　・・・`add`も編集内容も残る（コミットIDはgit logで見れるよ）
+ `git reset --mixed コミットID`　・・・`add`は消去、編集内容は残る
+ `git reset --hard コミットID`　・・・`add`も編集内容も削除
ファイルの状態は`git status`で確認してね　
    

## リモートブランチの内容をローカルブランチに取り込む方法
２種類のやり方がある。**fetch OR pull**
    
#### fetch
+ `git fetch リモート名`・・・fetch＝取ってくる
**※リモートからローカルに情報は落とすが、ワークツリーには取ってこない**
リモートブランチについては
`git fetch` をすると`remotes/リモート/ブランチ`というところに情報が入る
ワークツリーにも変更を取り入れたい場合は`git merge`をする。merge=統合
    
#### pull
+ `git pull リモート名 ブランチ名`・・・fetchとmergeを一度にする
**⚠️Pullは挙動が特殊なので気を付ける**
**今自分がいるブランチにpullされる**のでうっかり意図しないブランチに取り込んでしまうことが多い。
なのでfetch→mergeがおすすめ
    

## ブランチを統合する方法(mergeとrebase)

#### ◎前提の流れ

1. `git branch ブランチ名`・・・ブランチを新規作成する
2. `git checkout 既存ブランチ名`・・・↑で作ったブランチに入る
`git checkout -b 新ブランチ名`・・・ブランチを新規作成し、ブランチに入ってくれる。１、２の工程を一回で行ってくれる   
3. 新規作成したブランチ上でファイルの変更等行う。
4. `add`する
5. `commit`する
6. `git checkout 既存ブランチ名`・・・取り込みたいブランチに切り替える
7. 下２つの工程どちらかを行う

#### merge

変更内容を自分のブランチに統合する
+ `git merge ブランチ名`・・・自分が作ったブランチの変更を取り込みたい時
+ `git merge リモート名/ブランチ名`・・・リモートブランチの変更を取り込みたい時

#### rebase
二つのブランチを統合した時、統合する側の履歴が消え、
統合される側の履歴となり、まるで元々一直線にブランチを切っていたかのようにする。
**親コミットが変わる**。
+ `git rebase ブランチ名`

#### rebaseとmergeの違い

###### rebase

履歴をきれいに保つ
コンフリクトの解決が若干面倒（それぞれ変えないといけない）
履歴をきれいに保ちたいならコッチ

###### merge

コンフリクトの解決が簡単
コミットがたくさんあると履歴が複雑化する
作業の履歴を残したいならコッチ
変更の違いを見たい時は`git log`で見てね

## 変更を待避させる方法(stash)
コミットはしたくないけど、別のブランチで作業しないといけない時。
ワークツリーとステージでの**作業を無かったこと**にし、一時stashという場所に置いておく。
    
#### 一時避難
+ `git stash`・・・stash＝隠す
+ `git stash save ”メッセージ”`・・・メッセージを残して一時避難
    
#### ◎流れ
 ファイルを変更後`git status`をすると
 「ステージに上がってない変更があるよ。」か「コミットに上がってない変更があるよ。」と言われる。
その後`git stash`をし、再び`git status`をすると「nothing to commit, working tree clean」と言われる。
これで一時避難完了。
    
#### 避難した作業の一覧表示
+ `git stash list`・・・最新の番号が０
    
#### 避難した作業の復元
+ `git stash apply`　・・・最新の作業の復元。**ステージの状況は復元されない**
+ `git stash apply --index`　・・・ステージの状況も復元
+ `git stash apply スタッシュ名`　・・・特定の作業の復元。
スタッシュ名はlistで見れるよ。`stash@{数字}`のこと
    
#### 避難した作業の削除
+ `git stash drop`　・・・最新の作業の削除
+ `git stash drop スタッシュ名`　・・・特定の作業の削除
+ `git stash clear`　・・・全作業の削除
    
#### ◎豆知識
+ ブランチ間関係なく、stashという名の大きなファイルの隠し場所がある。
ブランチごとに管理しているわけではないので、`git stash apply`を行うと他ブランチで行った変更も全て取り込むことになる。
全て取り込みたくない場合は、`git stash save ”メッセージ”`でわかりやすいように
メッセージを残し、`git stash list`でメッセージのあるスタッシュ名を確認する。
その後、`git stash apply スタッシュ名`で特定のものを取り込む
        
    
## リバート
    
#### リバートとは
指定したコミットの内容を消して、新しいコミットを作成する
resetとの違いはrevertはコミットの履歴が残る
    
#### 使い方
+ `git revert コミットID`　コミットIDはgit logで調べられるよ
+ `git revert —no-edit`　エディタを立ち上げたくない時
+ `git status`をすると新しいコミットが生成されているのがわかる
    
#### オプション
+ `--no-edit`・・・エディタを開かない
+ `-n`・・・新しいコミットは作成しないけど、作業ツリーとインデックス（addされたステージの部分）の更新をする。ファイルを確認したり、調整したりしたい場合に使う。
    
## チェリーピック
    
#### チェリーピックとは
特定のコミットのみを取り入れたい時に使う。新しいコミットを作成する。
例）featureブランチでコミットA、コミットB、コミットCを作成し、mainブランチにコミットBだけを取り込みたいとする。
`merge`だと全ての変更が取り込まれてしまうが、`cherry-pick`だとコミットBだけ取り込むことができる。
こちらめちゃくちゃ使えます！！
私が実際に案件でチェリーピックを使うことになった状況を書いておきます！
    
#### マージとの違い
`merge`は全てのコミットを取り込むけど、その一部のみ取り込むことができるのがチェリーピック
    
#### 使い方
+ `git checkout ブランチ名`・・・取り込みたい側のブランチに切り替える。
+ `git  cherry-pick コミットID`・・・一つだけ取り込みたい時
+ `git cherry-pick コミットID_A..コミットID_B`・・・複数を取り込みたい時。
「..」を入れるだけ！
    
#### オプション
+ `-edit`・・・コミットメッセージを入れたい時
+ `-n`・・・新しいコミットは作成しないけど、中身だけワークツリーに入れたい時
    
#### 使った時
まず私は、ブランチAでコミットA・B・Cをした。
![スクリーンショット 2023-03-18 15.30.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269349/b03d6e93-1e97-8077-1be1-36e0a54a62d8.png)
ブランチBでコミットDをした。
![スクリーンショット 2023-03-18 15.31.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269349/345643a1-2749-a391-8f9a-03e1da5497a9.png)
そこで、ブランチBをプルリクをするのに
`git push origin ブランチB`でブランチBのみpushをした。
その後、Github上でコミット履歴を見てみるとコミットA・B・Cまで入っているんです！！！！
なんでだ！と思い先輩に聞いてみると、「ブランチAからブランチBを切ったのではないか」と言われ、
なんとなく心当たりがありました。
そこでmainからブランチ切ってファイル編集全部やり直し！？と思ったのですが、ここで使えるのがチェリーピックです！
まずブランチBで`git log`をしてコミットDのコミットIDをコピーします。
その後、mainから、ブランチCを切って`git cherry-pick コミットID`をします。
![スクリーンショット 2023-03-18 15.31.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3269349/7b4b0f3d-2cc1-3807-edb8-757475398acf.png)
これで完成です！
`git push origin ブランチC`でブランチCのみpushすると、
Github上でのコミット履歴がコミットDだけになってますっ！！！！
これはめちゃくちゃ使えますね。


## Git-flowについて

#### Gitflowとは
ブランチを使用する開発戦略のこと。これは開発するにおいてお決まりのようなもの
ただし、案件によって差異があるので、その案件のルールに則る。

#### ブランチの種類と使い方
+ main・・・最後は全てここへ。最新の状態でいたい。
**直接コミットすることはなく、mergeを行うためだけのブランチ。**
+ develop・・・開発中は全てここへ。mainから派生。
**直接コミットすることはない**
+ feature・・・実装する機能毎にfeature作成。
**必ずここで開発すること**。自作のブランチ名で開発をしてもいい。
merge完了したら削除。developから派生。
+ release・・・リリース時の微調整。developから派生。
+ hotfix・・・リリース後の緊急対応時に使う。mainからの派生。

## 最後に
色々調べて思いましたが、Gitはとても奥が深いですし、まだまだ他にもたくさんの機能があるので、完全に分かりきる。ということはとても難しいなと感じました。
ですが、今回記載しているものは業務で扱う頻度が高いかと思いますので皆さんのご参考になればとても嬉しいです！
といっても、やはり触っていかないとイメージを掴めないので練習用のディレクトリを作って、
たくさん練習していきましょう！
最後まで読んでいただき、ありがとうございました！