Git/Githubの備忘録

# はじめに
最初のハッカソンに参加したときに使って便利すぎって思ったので自分用にまとめる。
全然使いこなせてないから随時追記予定。
間違ってたら遠慮なしに教えてください。
ほなさっさと書きます。



# もくじ
[1. はじめに](#-はじめに)
[2. もくじ](#-もくじ)
[3. 概要](#-概要)
[4. 導入](#-導入)
[5. 基本の使い方](#-基本の使い方)
[6. いろいろな概念](#-いろいろな概念)
[7. 用語](#-用語)
[8. そのほかいろんなコマンド](#-そのほかいろんなコマンド)
[9. おわり](#-おわり)



# 概要
Git は分散型バージョン管理システム(VersionControlSystem)。
いろんな場所でそれぞれ開発できるのがつよつよ。
リモートリポジトリを介してそれぞれの進捗を引き継げるぜ。
過去のバージョンもとってこれるぜ。
Github はリモートリポジトリの提供をしてくれているホスティングサービス(サーバーを貸してくれるサービス。)。GitLabとかいうのもある。




# 導入
とりあえず入れ方。
gitをつかえるツール(?)はたくさんあるが、今回はgitとVisual Studio Code(以下VScode)を使う。
GUIのツールでSourceTreeがあるが、VScodeもGUI操作できるしいらんかな。。
基本的にWindowsでのおはなし。

#### ダウンロード&インストール&ログイン
VScode: https://code.visualstudio.com/download
Git: https://git-scm.com/
ここから自分の環境にあったインストーラ等を落としてインストールする。
VScodeはインストール時「エクスプローラーのファイル/ディレクトリコンテキストメニューに[Codeで開く]アクションを追加する」的な項目にちぇーーっく入れるとフォルダ右クリで直接フォルダを開けるようになる。べんり。
「git history」という拡張機能を入れておくと便利。

Github: https://github.com/
Githubでアカウント登録も。

#### パス設定
アドレスバーに「git-bash」と入力してカレントディレクトリで直接開けたほうが便利なのでパスを通す。
1. 検索窓でgitと入力して右クリック、ファイルの場所を開くとショートカットファイルがあるはず。
2. 元の場所を調べて(デフォルトだと: C:\Program Files\Git とかだと思う)pathをコピー。
3. 検索窓で環境変数と調べ、設定を開く。環境変数を開き、Pathに追加する。


#### 初期設定
1. メアドとパスワードを登録
    ```bash: git-bash
    $ git config --global user.email "your email"
    $ git config --global user.name "your name"
    ```
2. SSH通信の設定
    ```cmd: cmd
    rem ユーザーディレクトリに移動
    cd %userprofile%
    rem 鍵を生成
    ssh-keygen -t <鍵の種類> -C "<YOUR EMAIL>"
    ssh-keygen -t ed25519 -C "EMAIL"
    
    rem 何か聞かれるけどすべてenterで押し通す
    ```
    拡張子のないファイル(テキストデータ)の中身が秘密鍵、.pubが公開鍵。
    githubのsettingsのSSHandGPGkeysという項目にsshkey(""公開鍵"")を追加。
    これはpcとgithubとの通信に必要なので、通信したいｐｃ毎に必要なはず。
    ```cmd: cmd
    rem 疎通確認
    ssh -T git@github.com
    
    rem 最初に名前を決めてないとなんか聞かれるけどyesで押し通せば𝓼𝓾𝓬𝓬𝓮𝓼𝓼𝓯𝓾𝓵𝓵𝔂
    ```


# 基本の使い方
基本的には
1. リポジトリ(ソースとかを置いとく場所)を作成 or クローン
1. ローカルで作業
1. 変更差分を保存
1. リモート(github)に上げる
1. みんなの変更をリモートから貰う。
で2~5を繰り返す。


VScodeでCtrl + Shift + G でGit管理画面を出せる。
Ctrl + Shift + @ でコンソール画面を出せる。コンソールウィンドウの右上らへんの下矢印でコンソールの種類をGit bashに変えれる。
git-bashは現在の作業ブランチを表示してくれるので良い。

具体的なコマンドをまとめる
1. リポジトリ(ソースとかを置いとく場所)を作成 or クローン
    ```
    # リポジトリを作成
    $ git init
    # 作ったローカルリポジトリをgithub上のリモートリポジトリに紐づける
    $ git remote add <リモートリポジトリに付ける名前。基本はorigin> <URL>

    # githubからリモートリポジトリをクローンしてくる
    $ git clone <URL>

    # <URL> はgithubのリポジトリページの「<> Code ▼」を押すと出てくるHTTPSかSSHかGitHub CLIをコピーする
    ```
1. ローカルで作業
1. 変更差分を保存
    ```bash: bash
    # 変更差分をバイナリとして保存
    $ git add <変更があったファイル>
    # 変更があったファイルを一括で選択するなら . でおｋ
    # git add .
    
    # 変更差分をコミットとして保存し、リモートリポジトリを更新。
    $ git commit -m "<コミットメッセージ>"
    ```
1. リモート(github)に上げる
    ```bash: bash
    # 更新されたローカルリポジトリをリモートリポジトリに上げる
    $ git push origin <ローカルブランチ名>:<リモートブランチ名>
    # origin はリモートリポジトリを紐づけるために名付けられるデフォの名前
    # ローカルとリモートの名前が同じなら以下のように省略できる
    $ git push origin <ブランチ名>
    # リモートにない場合でも上がる。
    ```
1. みんなの変更をリモートから貰う。
    ```bash: bash
    # 他ユーザがリモートに上げた変更をローカルにも反映させる
    $ git pull origin <ブランチ名>:
    ```

これらに加えて、作業する際には **「ブランチを切る」** 。

ブランチ自体の説明は下の概念の項目で。
- 移動
- 切り方
- マージ

### 移動
作業をするブランチを移動する。
```bash: bash
# ローカルブランチの切り替えと変更の取り消し
$ git checkout <ブランチ名>
# 2019年のGit 2.23のリリースで追加されたswitchのほうがいいらしい
$ git switch <ブランチ名>
```
### 切り方
流れを増やして(生やして)スコープを限定して作業する。
AブランチからBブランチを切る例
```bash: bash
# AブランチからBブランチを切りたいときは、Aブランチに居る必要がある。
$ git switch <Aブランチ>
$ git branch <Bブランチ>

# ブランチの作成と切り替えを同時に。
$ git checkout <ブランチ名>
# 以下と同じ
$ git branch <ブランチ名>
$ git checkout <ブランチ名>
# switch で書くなら
$ git switch -c <ブランチ名>
```

### マージ
基本的にはAブランチにBブランチの内容をがっちゃんこする、ってこと。
AブランチにBブランチをマージする例
取り込む側に立って取り込まれる側を指定する。
```bash: bash
# AブランチにBブランチをマージしたいときは、Aブランチに居る必要がある。
$ git switch <Aブランチ>
$ git merge <Bブランチ>
```
一応マージには二種類あるらしい。
```bash: bash
# AブランチからBブランチを切った。
$ git switch Abranch
$ git branch Bbranch
```
ブランチBが切られたタイミング以降でブランチAにコミットの更新がなければ、ただAブランチの先端(？)にBブランチのコミット群を追加するだけだから `fast-forwardマージ`になる。
更新があれば `no-fast-forward` マージになる。

# いろいろな概念・用語
リポジトリ、ブランチとかの全体の理解ができるととりあえずいいかも。
## リポジトリ
ソースコードをはじめとした成果物、データ、アーカイブを保存しておく場所。倉庫や貯蔵庫の意味そのまま。
gitでは .git フォルダにGitが扱う内部データを格納する。
もちろんリモートとの紐づけもここで 管理してる ~~(と思う)~~ (.git/configに[remote "origin"] url = \<URL\> という形で保存されている)ので、これを消すとリポジトリとして認識できなくなる。
仮に新しくinitしても、そこに一つ目の.gitのコミットやブランチ情報その他はないため、リモートとのつながりもなくなり、根本の異なるブランチ≒別のリポジトリとして扱われる。
![repository.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491996/b579bf5c-e90a-0d48-b8c5-6a8d6de1f870.png)

### リモートリポジトリ
GithubなどのWeb上のホスティングサービスに置かせていただいているリポジトリ。
ここを介することで分散したクライアントたちのバージョンや進捗を整えれる。
### ローカルリポジトリ
ローカルの開発環境にあるリポジトリ。
gitはこことの差分を「変更」として感知してくれる。

ついでに add commit push の関係性の図解を。
#### 作業ディレクトリ(working directory)
.gitが配置されているディレクトリ。
このフォルダをVScodeで開いて(ctrl + k, ctrl + o)実際に作業する。

作業によって発生した「変更」を `git add <対象のファイル>` することでステージング領域にバイナリとして保存できる。
#### ステージング領域(index)
`add`により送られてきた差分・変更を保存する場所。
具体的には
.git/index: インデックス
.git/objects/: リポジトリのデータベース
に置かれる。

この差分に `git commit -m "<commit message>"` することでコミットを作成し、ローカルリポジトリを更新できる。

#### ローカルリポジトリ
`commit`により送られてきたコミットで最新コミットが更新される。

`git push origin <ブランチ名>` することでリモートにもブランチの更新を反映することができる。

![add commit push.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491996/e9b4cb4d-0619-1ee6-32f5-b06e4615c652.png)

## ブランチ
git の変更履歴はコミット単位で管理される。
コミットが数珠つなぎになった状態、そこから作業する流れを指定・管理するのがブランチ。枝や支流の意味そのまま。

ブランチモデルと言ってブランチの切り方にはある程度の決まりが作られてたりする。
今回はgit-flowについてかこーかな。
これはdevelopというブランチを軸に、各ユーザーがそれぞれの機能をfeature/hogeというブランチで切って作業する、というもの。
プラグインとしてgit-flowは同封されてるはず。

![git-flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491996/307434ab-fb5b-9b7f-e8b8-3a5177bf8a94.png)
丸はコミット、横矢印はコミットのつながり、下矢印はブランチを切る、上矢印はマージ。



- main
    - リリース用のブランチ。
    - 基本的に触らない。
- develop
    - この軸を中心に開発。
    - 複数開発なら管理者以外は触らない。
- feature/
    - 作業や機能ごとに切る。作業するユーザーはこのブランチを切る。
    - 一通り作業したらプッシュしてマージリクエストする。
    - featureは消してしまってよい。
    - 機能の意味そのまま。

他に
- hotfix
    - リリース後のえぐいバグとか緊急でしばかなあかんやつ。
    - mainから直接切って修正後mainとdevelopそれぞれにマージ。
- release
    - プレリリース用。
    - リリース予定の機能やバグフィックスが終了した状態のdevelopから切る。
    - 準備が整ったらmainとdevelopそれぞれにマージする。

などもある。


## 追跡ブランチ
gitは更新があったとき検知するわけやけど、何を監視して何と比較してるのか。下図を参考に。
それが `リモート追跡ブランチ`と `上流ブランチ`。
- 追跡ブランチ
    - ほかのブランチを追跡「している」ブランチ。
    - 例えば、
        - developブランチ(ローカルブランチ)はorigin/develop(リモート追跡ブランチ)を上流ブランチとしてそれを「追跡している」。
        - origin/developブランチはremoto/origin/develop(リモートブランチ)を上流ブランチとしてそれを「追跡している」。
    
    作業で出てくる「変更」は、ブランチとリモート追跡ブランチとの差。
    fetchやpullで貰ってくるリモートの更新は、リモート追跡ブランチとリモートブランチとの差。
- 上流ブランチ
    - 追跡されてる側。
- リモート追跡ブランチ
    - リモート(remote/origin/branch)を追跡しているブランチ
![追跡.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491996/ec6a6143-c4f5-c549-039c-9c7b0c3e2149.png)


## origin
リモート名のこと。慣習的にoriginという名前が用いられがち
```
$ git remote add origin <リモートのURL>
```
するときのorigin。
originという変数名にリモートのURLを置いているイメージ。

## コミットメッセージ
コミットする際にメッセージを必ず設定する。
基本的に
"[hoge]piyopiyo"
のようにカッコ内にコミット種を、そのあとにコメントを書く。
コードを見てわかるコメントよりは「なぜ」その変更をしたのかを書くほうが良い。
ex: [update]～のため、～を～に修正。

コメントは複数行書くこともできる。
公開範囲が広いものは英語で書いたほうがええかも。

コミット種をまとめる。
- add: 新規ファイル
- feat: 新しい機能
- update: 機能修正
- fix: 不具合バグ修正
- remove: 削除
- revert: 変更取り消し

- docs: ドキュメントのみの変更
- refactor: 使用に影響のないコード修正。
- style: 体裁を整えた。空白とかインデントとかセミコロンとか

- perf: パフォーマンス向上
- test: てすと

## pull
リモート追跡ブランチとリモートブランチとの差を `fetch` でとってきて、リモート追跡ブランチの内容を作業ブランチに `merge` して更新する。
この二つのコマンドをいっぺんにできるのが `pull`
```bash: bash
# リモートからリモート追跡ブランチに更新を落とす
$ git fetch origin <ブランチ名>
# 上流のリモート追跡ブランチを作業ブランチにマージする
$ git merge origin/<ブランチ名>
```


## マージリクエスト(プルリクエスト)
これはgitというよりホスティングサービス側が提供している機能。
個人開発であればマージは特に問題にならないが、複数開発の場合、レビューすることでコンフリクトの回避ややりとりの記録もできる。

### githubでのやりかた
1. pushする。
1. リポジトリのメニュー画面から `Pull requests` を押す。
1. `New pull request` を押す。
1. base とcompare のブランチを選ぶ。
1. `Create pull request` でリクエストを作る。
1. タイトルとコメントを書きリクエストする。
1. 管理者側はプルリク(送られてきてれば `Pull requests`を押すと一覧表示される)に対してCommitsやFiles changedを確認し、コメントする。
1. 管理者側はレビューが終了したら `Confirm merge`でマージする。

### .gitignore
このファイルにgit でコミットに含めたくない場合、github上にあげたくないファイルを追跡対象gitから除外できる。
ワイルドカードも使える。
`#`でコメントアウトできる

```.gitignore: .gitignore
# /を含まない
# .gitignoreが配置されているディレクトリ以下にあるこの名前のファイルフォルダを無視する。
file_or_folder

# 末尾にのみ/を含む
# .gitignoreが配置されているディレクトリ以下にあるこの名前のディレクトリを無視する。
directory/
# 後述の!との相性が悪いからディレクトリ自体を除外するより
direcotry/*
# のようにしたほうがいい。

# 末尾以外にのみ/を含む
# .gitignoreが配置されているディレクトリをカレントディレクトリとする相対パスで指定されるファイルフォルダを無視する。
/path/pathpath/file_or_folder

# 末尾以外も末尾にも/を含む
# .gitignoreが配置されているディレクトリをカレントディレクトリとする相対パスで指定されるディレクトリを無視する。
/path/pathpath/dirctory/

# !を先頭に置く
# 例外・無視しないを表す。上での設定を上書きできる。
# ただしフォルダ例外は上書きできない。
! path 
! directory/*.ext

# 空行や# で始まる行
# コメントとして認識
# test line


```
gitはファイルしか追跡しないのでからのフォルダはリポジトリに含めることができない。
追跡したい空フォルダに.gitignoreを入れて
```
! .gitignore
```
することで疑似的に追跡できる。





# コマンドまとめ
```
# リポジトリの状況を確認
$ git status

# リモートリポジトリをローカルにクローン
$ git clone <URL>

# 特定のブランチを指定してクローン
$ git clone <URL> -b <落としたいブランチ名>

# 差分をステージング領域にバイナリとして保存
$ git add <対象のファイル。 "." で指定するとすべて>

# 差分に名前を付けてコミットとして保存
$ git commmit -m "<コミットメッセージ>"

# コミットをリモートリポジトリに反映させる
$ git push origin <ローカルブランチ名>:<リモートブランチ名>
# ローカルとリモートの名前が同じなら省略される
$ git push origin <ブランチ名>

# ローカルブランチ一覧
$ git branch

# リモート追跡ブランチを含むローカルブランチ一覧
$ git branch -a
# この際、リモートのブランチが反映されない場合がある。その際は git ls-remote を使ってリモートの更新を受け取る。

# ブランチが存在するか確認
$ git branch -a <検索したいブランチ名>

# ブランチの作成
$ git branch <ブランチ名>

# ローカルブランチの切り替えと変更の取り消し
$ git checkout <ブランチ名>
# 2019年のGit 2.23のリリースで追加されたswitchのほうがいいらしい
$ git switch <ブランチ名>

# ブランチの作成と切り替え
$ git checkout <ブランチ名>
# 以下と同じ
git branch <ブランチ名>
git checkout <ブランチ名>
# switch で書くなら
$ git switch -c <ブランチ名>

# ブランチの削除
$ git branch -d <ブランチ名>

# ブランチ名変更
$ git branch -m <変えたいブランチ名>  <新しいブランチ名> 

# リモートリポジトリの最新の履歴の取得
$ git fetch origin <ブランチ名>
$ git merge <追跡ブランチ名。例えばorigin/develop>

# 上二つのコマンドは一度にできる。他ユーザがリモートに上げた変更をローカルにも反映させる
$ git pull origin <ブランチ名>:

# 送るブランチを空にする、つまりリモートブランチの削除。
$ git push origin :<リモートブランチ名>

# 今いるブランチに指定したブランチを取り込む
# git merge <取り込むブランチ名>

# 根元の異なるブランチを強引にマージ
$ git merge --allow-unrelated-histories <取り込むブランチ名>

# リモートの更新を確認
$ git ls-remote
```
# おわり
Gitマスターに俺はなる！！


## 参考の神サイトたち
サル先生のGit入門〜バージョン管理を使いこなそう〜【プロジェクト管理ツールBacklog】
https://backlog.com/ja/git-tutorial/
Git-flow ～Gitのブランチモデルを知る～ | バージョン管理システム入門(初心者向け) 
https://tracpath.com/bootcamp/learning_git_git_flow.html
GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~ - Qiita
https://qiita.com/shizuma/items/2b2f873a0034839e47ce 
GitのHEADとは何者なのか - Qiita
https://qiita.com/ymzkjpx/items/00ff664da60c37458aaa 
Git で「追跡ブランチ」って言うのやめましょう - Qiita 
https://qiita.com/uasi/items/69368c17c79e99aaddbf 
【初心者向け】git fetch、git merge、git pullの違いについて - Qiita 
https://qiita.com/wann/items/688bc17460a457104d7d 

ありがとうございました。