GitとGithubの使い方を忘れないために

#初めに
![スクリーンショット 2022-01-20 9.27.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/b5a91b90-e113-178c-2c11-5094abf6fa61.png)
さて、今回はGitとGithubについてまとめていきたいと思います。こんな経験はないですか？☞【GitとGithubの操作がいまいちわからない】【Gitは過去に何度か触ったことがあるけど少し触っていないと忘れてしまう】☜私はあります（ ;  ; ）
しかし、GitとGithubを使いこなせることは近現代のエンジニアにとってマストであると感じることも多々あるため、避けては通れないでしょう。。**そんなわけで、今回はGitとGithubの操作や、これまで私がお世話になってきた参考資料についてメモを残していきます！**網羅的には書けないでしょうが、ゼロから始める方に役立てばと思います。

**今回の章立ては6本です**

+ 1, Gitとは（Gitについて理解を深めていきます）
+ 2, Gitの基本操作まとめ（実際に自分で動かしてみて、メモがわりに見れる場所にします）
+ 3, GitとGithubを実際に使ってみる（写真を混ぜながら使用方法をメモしていきます）
+ 4, Git用語の確認
+ 5, まとめ
+ 6, 参考資料：学習サイト（私が学習に使用させて頂いていたサイトや公式ドキュメントの紹介です）


（追記）私自身もこの記事を書き始めている時は、忘れていることもたくさんあって勉強になりました。

#1, Gitとは
Gitとはバージョン管理システムです。1つのファイル（ソースコード）やファイル（プロジェクト）に対して、加えられる変更を記録するシステムです。Gitではリポジトリ（プロジェクトの単位・システムの単位）でファイルを管理します。Githubはリモートリポジトリをwebで見れるようにしたものです！今回は実際にGithubにリポジトリを作成してGitで操作するところをゼロからメモしていきたいと思います。詳しい内容は**[Git公式](https://git-scm.com/book/ja/v2)**が綺麗にまとめてくれているので割愛します。

* Git管理以前の開発の問題点
・以前のバージョンに戻すことが難しい
・複数人で開発することが難しい

* Gitを使用することで以下のことが可能になりました
・ ファイルのバージョン管理
1, ファイルやプロジェクトを以前の状態まで戻す 
2, 過去の変更履歴を比較する
・ 他の開発者との共同開発
1, 誰が最後に修正したか、誰がいつ問題点を混入させたかを確認する
2, 複数人が同じファイルを修正した際に自動でマージ(統合)する
3, 複数人が全く同じ個所を修正した際に競合したことを知らせる

#2, Gitの基本操作まとめ
##【Step1】
まずは[Git](https://git-scm.com)をダウンロードします。

gitの確認

```
git --version
```
-> git version 2.32.0 (Apple Git-132)

##【Step2】

+ アカウントを作成しましょう。個人識別情報を設定します。

**ユーザー名の設定**

```
git config --global user.name "あなたのUser名"
```

**メールアドレスの設定**

```
git config --global user.email "あなたのメールアドレス@gmail.com"
```

+ 設定を確認しましょう。


```
git config --list
```
-> user.name "あなたのUser名"
-> user.email "あなたのメールアドレス"

##【Step3】
* 秘密鍵・公開鍵のペアを生成
ssh-keygen -t rsa -C "あなたのUser名@gmail.com"
-> 実行すると3回入力を求められるが全てそのままEnterを押しましょう。（パソコンのログインパスワードを入れることもあります）

~/.ssh/id_rsa.pubという名前のファイルが公開鍵なので

```
less ~/.ssh/id_rsa.pub
```
で中身を表示させてコピーしましょう。こんな感じの公開鍵が画面に出ると思います。

ssh-rsa
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx= あなたのUser名@gmail.com
**コピーしたら「q」を押してコマンド画面に戻ります**

##【Step4】
**公開鍵情報をGitHubに登録しましょう**
• 画面右上のアイコン→「Settings」の順でクリックします

![スクリーンショット 2022-01-19 21.07.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/05233b82-6fea-ab6b-a98b-3398e230cf98.png)

**公開鍵情報をGitHubに登録しましょう**
• 次に表示される画面の「SSH and GPG keys」→「New SSH key」の順 でクリックします

![スクリーンショット 2022-01-19 21.16.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/94b92794-1fbf-988a-d90e-be816f87ad78.png)

##【Step5】
**公開鍵情報をGitHubに登録します**
• Title:使っているPCがわかる名前にしましょう(MacBook Proなど☜私はSeffeineにしました) 
• Key:先ほどコピーした公開鍵情報を貼り付けましょう
• 「Add SSH key」をクリックしましょう

#3, GitとGithubを実際に使ってみる

##【Step1】
リポジトリの作成（今回はGithubでリモートリポジトリを作成）
「+▼」からNew repositoryを選択してリポジトリを作成します。

**Natural_Language_Processing**というリポジトリを作成しました。

##【Step2】
Git CloneでリモートリポジトリにあるNatural_Language_Processingをローカルにコピーします。git cloneの後にSSHのコードを貼り付けてください。

```
git clone git@github.com:seiji0203/Natural_Language_Processing.git
```
##【Step3】
今回はお試しでNatural_Language_Processingのリポジトリにファイルを作成します。
まずはリポジトリのある階層に移動します。私の場合は

```
cd /Users/xxxxxxxxxxx/Natural_Language_Processing
```
こんな感じで移動します。[ターミナル](https://qiita.com/seiji1997/items/4e2c59ad10a0fe51c73c)の操作は以前私がメモした記事があるので、適宜参照してください。以下のようにファイルを作成します。

今いる階層にファイルを作成

```
touch ◯◯.txt
```
あるいは、ファイルを指定してvim上で加工する

```
vi(vim) ◯◯.txt
```

Vimエディタの使い方 (commitの編集方法)
① ターミナルでgit commitを入力する
② Vimエディタが立ち上がる
③ 半角英数字に入力を切り替える
④「i」を入力する （挿入モードになる）
⑤ コミットメッセージを入力する
⑥「esc」を押す （ノーマルモードに戻る）
⑦「:wq」を入力してエンターを押す
(commitメッセージを保存してエディタを閉じる)

これでNatural_Language_Processingの階層にfile1, flie2を作成しました。
**コメント**
file1 : this is file1
file2 : this is file2

##【Step4】
以下のコマンドでファイルがあるのを確認しましょう。

```
git status
```

![スクリーンショット 2022-01-19 22.53.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/b09c1dd1-af08-fcf1-f08c-c9d2362d6617.png)

この段階ではこれらのファイルたちはGitに管理されていないので、以下のコマンドを実行して

```
git add file1.txt
```
git statusで確認するとfile1がステージング（緑色の状態）されたのが確認できます。

![スクリーンショット 2022-01-19 22.54.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/8ddbc323-673e-e588-d713-a84755a6fe9c.png)

このようにgitではファイルごとに選択して管理することができます（ちなみにgit add .　とすると全てのファイルをステージングできます）。実行してみてください、二つのファイルがステージングされているのが確認できると思います。では、file1,file2を保存してみましょう。

##【Step5】
gitで保存する場合には以下のコマンドを使用します。

```
git commit -m "this is my first commit"
```
次にfile1の「this is file1」を「初めての変更です」と編集します。git statusで確認すると、modified: file1.txtと表示されます。

![スクリーンショット 2022-01-19 23.04.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/6c46c81e-007b-b912-be76-62f70f418c81.png)

そしたら、git add .でステージングして、git statusで確認しましょう。確認できたら、

```
git commit -m "this is my second commit"
```
と2回目の保存をします。

```
git log
```
と打つとこれまでの記録が見れます。

![スクリーンショット 2022-01-19 23.11.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/4d58e7e6-8bed-4cd0-d4d2-c73653660e19.png)

##【Step6】
さて、ステージングしたファイルをgithubにアップロードします。

```
git push origin
```

実際にGithubを確認するとアップされているのが確認できます。

![スクリーンショット 2022-01-20 9.16.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/04376512-dcf4-04f8-8243-fe5a0d469abf.png)

コメントも確認すると、先ほどの変更も確認できます。

![スクリーンショット 2022-01-20 9.16.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/24a081de-f7b8-5f06-7747-55cd4dd3ee28.png)


# 共同開発するときに
まずは以下の図を見てください。ざっくりこんな感じのイメージを作成しました。これは**SeffeineとCaffeineの共同開発**について図にまとめたものです。先程までにSeffeineはリモートに対していくつかのコミットをプッシュしました。この状態でCaffeineが新しく開発に加わることになった想定についてみていきます。

![スクリーンショット 2022-01-20 10.23.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/af61f050-8c7b-1a10-b78e-17969c21d777.png)
####まずはCaffeine側からみていきます。

①で最新のリポジトリをクローンします（これまでSeffeineが行ってきた内容がCaffeineのローカルにクローンできます。）。

②では先程と同様にvimでfile1に変更を加えます。

③変更した内容を「git add .」でステージングして「git commit –m”4回目のcommitです”」と変更をcommitします。

④git logでコミット内容を確認します。

⑤git push originを行うことでステージングした内容をリモートに対して変更を行います。

####次にSeffeine側の操作を確認して行きます。

①まずは「git log」で状況を確認します。しかし、SeffeineはまだCaffeineが変更した内容をGithubから得られていないので、commit内容（4回目のcommitです）は表示されません。「git clone」でデータを得るのは新規の時だけなので、ここでは「git pull origin」とします。すると、Seffeineのローカルリポジトリに最新のリポジトリ情報がダウンロードされます。

②「git log」で確認できます。

その後は、これを繰り返すことで変更を更新しながら共同開発ができます。

#branch
次にbranchについて考えて行きます。**branchとはgitの変更履歴を枝分かれさせる機能**のことです。では以下の図を確認しながらbranchを学んでいきましょう。
本番稼働している大事なシステムでのcommitの歴史をmasterと呼びます。このmasterの環境を壊さないようにbranchで歴史を作って行きます。それにより、master側には危害を加え無いで、開発を行うことが出来るので、masterは安全です。

![スクリーンショット 2022-01-20 12.02.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/4e1af8bc-8cc4-efdb-3e23-c182b6867ba3.png)
####まずはCaffeine側からみていきます。

①git checkout -b develop master
まず、masterからdevelopという新しいブランチを切ります。

②git branch
「git branch」とすると、今作成したdevelopのbranchにいることが確認できます。「git checkout master」とすれば、developからmasterに移動することができます。「git branch」で確認します。「git checkout master」とすることで、またdevelopに戻ることができます。

③vim file1.txt
ファイルに変更を加えます。「file1の5回目の編集です」。

④add . 
ステージングします。

⑤git commit -m "5回目のcommitです"
変更をcommitします。

⑥git push origin develop
リモートに対してプッシュします。これによりリモートにプッシュされます。

####次にSeffeine側の操作を確認して行きます。

①git pull origin
ローカルにdevelop branchをダウンロードします。

②git branch
masterにいることが確認できます。

③git checkout develop
developのbranchに移動します。

④git log
logを見て、変更を確認します。

⑤git merge develop
内容が良ければmasterにmergeします。mergeするにはmerge先に移動する必要があるので、「git checkout master」として移動します。そしてmasterに対してdevelopをmergeしたいので**「git merge develop」**とします。

#pull request
githubを使ってもっといい感じにタスクをこなす！わざわざSeffeine側のローカル上にpullして確認して、フィードバックする。みたいなことをしなくても、Caffeineが作成したdevelop2をgithub上で確認してコメントすることができます。最終的にはmerge pull requestとすることでgithub上でmergeまで出来るのです。最近ではこちらが主流になってきているらしいです！では見てみましょう。

![スクリーンショット 2022-01-20 12.23.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/83ddf121-3f3e-348a-f480-2558450fe64e.png)
####まずはCaffeine側からみていきます。

①git checkout -b develop2 origin/master
次の新しい機能を開発するためにdevelop2というbranchを切ります。

②git add .
ステージングします。

③git commit -m "6回目の編集です"
変更をcommitします。

④git push origin develop2
これでdevelop2がgithubにプッシュされました。そうするとgithubには新しくpull requestを作ると出るので、github上でpull requestを作成します。これは、develop2というbranchを作成したので、masterにmergeしてください。という依頼になります。

####次にSeffeine側の操作を確認して行きます。

①github上でpull requestをレビューします。

②merge pull request
問題のない状態になったら、merge pull requestをgithub上で押すことでdevelop2 branchがmasterにmergeされます。


#同じブランチで作業するときに気をつけること
SeffeineとCaffeineが同時に同じbranchで開発を行っている状況を考えます。この時、先にSeffeineがfile1に変更を加えてcommitします。Caffeineは同じdevelop branchでfile2に変更を加えcommitします。するとSeffeineは無事にpushできますが、Caffeineは**reject~~~fetch first**というエラーが発生します。この時、先にpushされたSeffeineの歴史の方が正しいとgithub上では認識されているので、これを以下の手順で解決して行きます。

![スクリーンショット 2022-01-20 13.15.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/8ddeef43-06d4-70ab-ab43-8114264ab473.png)
####まずはCaffeine側からみていきます。
①git pull origin
ローカルにdevelop branchをダウンロードします。

②git branch
masterにいることが確認できます。

③git checkout develop
developのbranchに移動します。

④vim file1.txt
ファイルに変更を加えます。「file1の7回目の編集です」。

⑤add . & git commit -m "7回目のcommitです"
ステージングと変更をcommitします。

⑥git push origin develop
リモートに対してプッシュします。これによりリモートにプッシュされます。

####次にSeffeine側の操作を確認して行きます。

①git fetch origin
リモートサーバー側にある最新のdevelop branchを取得します。

②git branch -a
リモート側も含めた全てのbranchを表示します。すると現在作業しているdevelopが緑になっていることが確認できます。そのときに赤字でremotes/origin/developとSeffeineが変更したdevelopも確認できます。

③git merge origin/develop
このときに、Seffeineが作成したdevelopをmergeしたときにこのようなコマンドを打ちます。

④前述のVimエディタの使い方 (commitの編集方法)を参照
するとVimが開いて、merge　commitのためのcommitメッセージを求められます。これによってリモートのdevelopを手元のローカルdevelopにmergeできました。

+ **git pull develop** : pit pull developとはgit fetch originとgit merge origin/developを合わせたものになります。一度に実行できます。developはmergeしたいbranch nameになります。これでリモートにpushできる状態になります。

##rebase
「git rebase」とは、マージと同じように、ほかのブランチのリビジョンを取り込むコマンドです。このようなコマンドもあるので一応確認しておきます。

**これまでのやり方**

```
git fetch origin 
git merge origin/develop
Get push origin
```
**rebase**

```
git fetch origin 
git rebase origin/develop develop
Get push origin -f （-f : ローカルを正として強引にリモートにpush）
```

![スクリーンショット 2022-01-20 13.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896292/259e83fd-1987-0851-f495-ffedc63ff1c0.png)

イメージとしてはこんな感じになるので、rebaseの方がcommit treeが綺麗になります。こmergeかrebaseかについては様々な意見があると思うので割愛します。一応私の好きな記事を貼っておきます。

https://nvie.com/posts/a-successful-git-branching-model/

##CONFLICT
同じファイルの同じ行を変更した場合に「conflict」と以下のようなエラーが発生します。

```
<<<<<<<HEAD
flie1の6回目の編集です。
=======
file1の7回目の編集です。
>>>>>>>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

この競合状態を直します。

```
file1の7回目の編集です。
```
行を削除して、編集内容を合流させます。fix conflicts and run "git commit"と出るので、「git commit -m "conflict解消"」とコメントします。

##reset
file1と2に変更を加えます。しかし変更内容が要らなくなった時に便利なコマンドです。

```
git reset --hard HEAD
```
これにより編集した内容がresetして最終commitした状態に戻してくれます。

##stash
branchを間違えて編集した場合に、stashコマンドを実行することで編集内容をgit内に一旦格納できます。

```
git stash
```

本来のbranchに移動してからstash popコマンドを打つことでstashでgitに格納した内容を呼び出すことができます。

```
git stash pop
```

#4, Git用語の確認

####init
「git init」は、リポジトリを作成するためのコマンド

####status
「git status」は、ワーキングディレクトリやインデックスの状態を確認するためのコマンド

####add
「git add」とは、コミット対象ファイルをインデックスに登録するためのコマンド
これでgitにステージングできる（commitできる状態になる）
git add ファイル名

####commit
「git commit」とは、インデックスにあるファイルの変更内容を「コミット」するためのコマンド。コミットとは、ファイルの変更内容を「リビジョン」としてローカルリポジトリに残すこと。コミットする際には、必ず変更内容などを記述した「コミットメッセージ」を添えて実行する必要があり
変更を加えた内容についてコメントを残す
git commit -m "first message"

####log
「git log」とは、リポジトリにあるリビジョンを確認するためのコマンド
Aさんが作成したリポジトリにBさんがgit cloneして変更を加えた。Bさんがgit pus originした内容をAさんが確認したい。その時はAさんはgit pull origin を実行して、git logをすることで確認できる。

####remote
「git remote」とは、ローカルリポジトリで指定するリモートリポジトリの追加や削除をおこなうためのコマンド

####pull request
Branchしたリポジトリのファイルを開発した。branchの内容をmasterにマージしてほしい。この時にプルリクエストを行う。

####push
「git push」とは、ローカルリポジトリの内容をリモートリポジトリに反映させるためのコマンド
Gitステージングされているファイルをgithubにプッシュする
 git push origin
 
 同じbranchでそれぞれ開発して、それぞれでpushすると先にpushした方が勝つ。その場合はリモートのリポジトリからpullしてきて、手元のデータとマージする（fetch）

####branch
「git branch」とは、ブランチの確認や作成、削除などをおこなうためのコマンド
Gitのコミット履歴を枝分かれさせることでができる（メインはmaster）。
とある時点から枝分かれさせることで異なる歴史を形成できる。その後合流できる。本番稼働している大切な環境（master）を保持したまま、branchで開発することで、masterにマージするまでmasterには干渉しない。
 
####checkout
「git checkout」とは、ワーキングディレクトリを特定の状態に変更するためのコマンド
「git checkout file」で、ファイルを最新リビジョンと同じ状態に戻します
「git checkout revision_number」で、指定したリビジョンのブランチを作成します
「git checkout branch」で、指定したブランチに切り替えます

####clone
「git clone」とは、リモートリポジトリをローカルリポジトリに複製（コピー）するためのコマンド

####fetch
「git fetch」とは、リモートリポジトリの情報をローカルリポジトリに反映するためのコマンド
git fetch origin

####merge
「git merge」とは、特定のブランチやリビジョンを、現在のブランチに取り込むためのコマンド
git merge origin/branch名

####pull
「git pull」とは、「git fetch」と「git merge」の２つをまとめて実行するコマンド
git pull origin

####rebase
「git rebase」とは、マージと同じように、ほかのブランチのリビジョンを取り込むコマンドです。
git fetch origin 
git rebase origin/develop develop
Get push origin -f （ローカルを正として強引にリモートにpush）

####diff
「git diff」とは、「ワーキングディレクトリ」と「インデックス」の差分を表示するためのコマンド

####reset
「git reset」とは、コミットやインデックス登録をリセットするためのコマンド
Git reset --hard HEAD （最終コミットの状態に戻せる）

####gitstash
Git stash（branch1で間違えて作業している場合、git stashでcutしてgit checkoutでbeanch2に移動してgit stash popをすることでペーストできる）
git stash pop

#5, まとめ
僕も最初は全然わからなくて一生使わないだろうなとか思っていました。しかし、どんなものでもそうですが、慣れると大変便利に感じるものです！とはいっても、僕もまだまだ使いこなせていないので、他の方のGit使用方法や公式ドキュメント、書籍など参考資料でどんどん学んでいきたいと思います！！一緒に楽しいGitライフを送りましょう！！

#6, 参考資料：学習サイトまとめ
> 1. [【Pro Git：日本語】](https://git-scm.com/book/ja/v2)
> 2. [Git](https://git-scm.com)
> 3. [LearnGitBranching](http://k.swd.cc/learnGitBranching-ja/)
> 4. [ギットクエスト:ゲーム感覚で学習](http://unit8.net/gq/)
> 5. [【初心者】Gitコマンドの使い方を体系的に覚える【一覧あり】](https://kitsune.blog/git-command)
> 6. [A successful Git branching model](https://nvie.com/posts/a-successful-git-branching-model/)