Git超入門「出来て当たり前、SSHでGitHub」の練習

業界によってはGitを扱えることが現場においてかなりベーシックなスキルになっていると思います。あまり最新の技術をばりばり扱っているわけでない現場であっても同様だと思います。また、たとえ普段は別のバージョン管理システムを用いている場合でも、（案件毎など）突発的にGitでの作業が必要になることもあります。

Webに関してはGithubやGitlab上でGitでのソースコード管理を行うことが業界のデファクトスタンダードとなってかなり経つので、扱えることが当たり前と考える人も多いです。SSHの扱いも同様です。

もし今まで（幸運なことに？）Gitを扱うことなくやってこれていたり、これからそういう業界を目指しているという方は、Githubも無料でプライベートリポジトリの作成が行えるようになったので、下記手順を行ってSSHやGitの練習をしっかり行っておきましょう。

この記事ではGitの利便性などには触れず、あくまで練習のための流れを説明します。細かい環境の違いなどでエラーが出ることもあるかもしれませんが、この流れの上で出るエラーはググったらすぐに解決するものが多いはずです。そこまで含めた練習テンプレートとしましょう。

# 先にSSHの準備
## SSHを使うとこんなことができる

SSHはGitのための仕組みではありません。主にサーバを扱うエンジニアがよく扱うものではありますが、下記にどのような場合に使われているかのイメージしやすい一例を。

- （所謂サーバなどの）リモートマシンに、鍵ファイルだけでログインできる（パスワード管理いらない）
- リモートマシンを操作する
- FTPをセキュアな通信越しに使える
- セキュアな通信でGithub（Gitlab, Backlog）のリポジトリ操作ができる

などなどなど。「関係ねー」って思った人も多いかもしれませんが、扱えて損はないです。（守備範囲が爆広がりします）

## SSHには鍵が必要
SSHの仕組み的にはパスワードでの接続も可能ではありますが非推奨であり、接続される側のサーバなどの環境構築時にはパスワードでのSSH接続をさせないように設定する慣習があります。

そこで、パスワードの代わりに接続の認証に用いられるのが鍵ファイル方式です。

推奨されるssh関連の管理ディレクトリに移動。Macではだいたいここがデフォです。

```
cd ~/.ssh
```

鍵を生成するコマンド

```
ssh-keygen -t rsa
```

基本的にはエンター連打でよいですが、ファイル名は適宜変更しておくことおすすめします。

ファイル名の例）id_rsa_github_account

account部分に自身のユーザー名などをいれておくとわかりやすいです。
状況によってはパスフレーズを設定したほうがいいこともあるので留意しておきましょう。

## 二つのファイルが作成される
鍵には「公開鍵」と「秘密鍵」があります。公開鍵は外に出しても（他の人に見られても、どこかに登録しても、公開しても）大丈夫、秘密鍵はローカルマシンの中だけで管理しておく（公開しない、送信なども行わない）のが原則です。

この例のまま作成した場合は、

- 秘密鍵：id_rsa_github_account
- 公開鍵：id_rsa_github_account.pub

となります。

### 接続のイメージ

- 公開鍵を接続先に登録しておく。・・・①
- 接続時に秘密鍵をもって接続先に問い合わせをすると、・・・②
- 接続先がその秘密鍵と登録されている公開鍵を検証して、・・・③
- ちゃんとあっていれば接続させてもらえる。・・・④

という感じです。

## githubに公開鍵を登録する

右上のアイコン - `Settings`

![go-to-setting.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/03f2e89e-abe4-d5f1-7b6c-512cef7b0d0e.jpeg)

`SSH and GPG keys`

![regist-ssh-key-on-github.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/c97a11cd-78d7-ad97-f90f-5594a37faec3.jpeg)

`New SSH key`ボタン

- Title

任意。（マシン名や鍵ファイル名などを推奨。あとで必要のなくなった鍵などは公開鍵であっても削除するべきなので、どのマシンからの接続のために登録した公開鍵なのか判別できるようにしておきます。）

- Key

`.pub`ファイルの内容を過不足なくコピペする必要があります。
とりあえず簡易的にはターミナル上でこのようなコマンドにて表示された内容をコピー、githubのKey欄にペーストして`Add SSH Key`をクリックして登録しておきます。①

```
cat id_rsa_github_account.pub
```


先程の`SSH Keys`一覧画面に表示されていればOKです。

## 接続確認をする

今回の流れでは、SSH接続するための「sshコマンド」は以下のようになります。

```
ssh -T git@github.com -i ~/.ssh/id_rsa_github_account
```

これはsshコマンドの基本が

```
ssh (オプション) (ユーザー名)@(ホスト) -i (秘密鍵ファイル)
```

なので、上のコマンドの和訳的には、

```
「gitというユーザー」で「github.comというサーバー」に「id_rsa_github_accountという秘密鍵ファイル」をもって「-Tオプション」でSSH接続します
```

という意味のコマンドになります。これが②

このコマンドで、下記のように表示されればOKです。

```
Hi (user-name)! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.
```

これは「接続はばっちりです、でもコマンドを実行するような機能は提供していないので、接続を切りますね。」とgithubからのメッセージです。③と④

# リポジトリを作ってみる
ついにGitの話です。

サンプルとなるリポジトリを作ってみましょう。なんでも大丈夫ですが、差分がわかりやすいようにテキスト情報で構成されているものがよいでしょう。

htmlばかりのこのようなファイル構成を作成してみました。

```
git-test-prj
│  └─ index.html
├─dir1
│  ├─ 1-1.html
│  └─ 1-2.html
└─dir2
   └─ 2-1.html
```

単純なテスト目的ならもっとシンプルでもいいですが、練習ならディレクトリや複数のファイルを用意しておきましょう。

## gitリポジトリ化する
リポジトリとは、ソースコードと、今までの変更履歴、および、設定のかたまりみたいなものです。リポジトリにする＝init(=initialize=初期化)と言われたり、ローカルリポジトリの作成といったりします。

### appを利用する

#### Fork
File - Init New Repository

#### SourceTree
Create

### コマンドで行う

```
cd /path/to/proj/
git init
```

## コミットする
リポジトリはコミットの積み重ねにより成り立っています。

コミットとはどのようなファイルが追加されたか、どのファイルにどのような変更が加えられたか、もしくは、なにが削除されたのかの情報です。これらの履歴自体と、その時点のファイルの状態を保存することをコミットと呼びます。前回のコミットから今の状態までが変更になります。

これらの情報を随時保存しておくことにより、いつ・だれが・どのような変更を加えたのかが管理できるようになります。また、それらの変更を区分したり、複数人が同時に様々な作業をできるようにする機能もありますが、今回はその説明は省きます。

現在は**新規の４ファイルが追加された**という変更のある状況です。

### 状況を確認する
appを利用している場合は、わかりやすく新規４ファイルが変更点として表示されているでしょう。

コマンドでは以下のように表示できます。

```
$ git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        dir1/
        dir2/
        index.html
```
正直わかりにくいですね。
（もっとわかりやすく表示も可能ですが、オプション覚えるの苦手なんで…なのでクライアントAppの利用をおすすめします）

### ステージする
どの変更を今回のコミットに加えるか決めていくことを**ステージする**と言います。
（コマンド的に**Addする**と言ってもいいかと思うのですが、聞いたことがないと思います）
ファイル単位でも変更点単位でも可能です（が、変更点単位をコントロールするのは少し大変なのでappを使っていない限りお勧めできません…）

４ファイル全てコミットしてしまうので、Stage allボタンなどが便利です。

コマンドでは下記で同じ意味になります。
```
git add *
```

### コミットする
ついにコミットボタンを押す！前に、コミットのためにはコミットコメントが必要になります。

appの場合はファイルステータス画面や、Changes画面でステージされている内容と、下部にコメント入力欄が表示されているかと思います。ここに任意のメッセージを入力します。

一番初めのコミットは`initial commit`とかになっているプロジェクトが多いです。お仕事などでルールや規約がなければそれが一番わかりやすいかと思います。

内容を確認の上、コミットボタンを押すことで晴れてコミット完了です！

コマンドでは下記となります。コメントをつけてコミットを実行、というようなイメージでしょうか。
```
git commit -m "initial commit"
```

### コミットを確認する
appではコミット一覧画面に表示されているかと思います。

コマンドでは`git log`ですが、これもオプション付けないと見づらいかと…

これで、コミット履歴の存在するリポジトリができました。

## 余談）Gitリポジトリではなくすには
さて、今までの履歴を全て削除し、新たなリポジトリとして管理しなおしたくなることがあるかもしれません。

そのディレクトリがGitリポジトリであるのは、`git init`コマンド実行時に生成された`.git`ディレクトリの有無によります。sourcetreeなどにブックマーク情報は保存されていますが、都度`.git`の中身を参照しているだけのようです。（環境によっては隠しディレクトリです）

なので、`.git`ディレクトリを削除してしまえば、過去のコミット履歴や接続情報などは消えてしまいます。
逆に言うと今までの開発履歴という財産が失われるという意味でもあります。

### 余談の余談）ミスった！と思っても慌てず。

この非リポジトリ化は、例えばプロジェクトスタート時や、ローカルマシン上で実験している際など**のみ**有効で、コミットを修正したりコミット前に戻したりという方法もたくさん存在しますので、必要になる前に習得しておいても良いかもしれません。プッシュ前のローカル環境上でのコミットミスなどのGitの過ちは些細なものです。落ち着いて対処しましょう。

ちなみに、筆者のやらかし含め、周りで起こった事をあげてみると
- コミットをミスって、慌ててなぜかマージ（割と些細なレベル）
- コミットをミスって、慌ててむしろプッシュ（先輩が慌てるレベル）
- コミットをミスって、慌ててコミットを削除（作業した内容にさようなら）
- コミットをミスって、慌ててディレクトリごと削除（ローカルでの履歴全てにさようなら）

慌てず相談しましょう。

# Githubにリポジトリ（の入れ物）を作る
Github上でリポジトリを作成します。これは今作ったリポジトリの同期先だと思ってください。

少し混乱するかもしれないのは、「リポジトリってさっき作ったよね？」ってことかと思います。これはリモートリポジトリとローカルリポジトリという概念があることに起因しますが、この辺りの詳細はおググりくださいませ。

ちなみに、この辺りの流れは人によっては逆の、Githubで（ほぼ空っぽの）リポジトリを作成して後述するクローンを行いローカルマシン上にて最初のファイルを作成し始める人もいます。（Github公式などはそちらを推奨しているようです）

## いざ
きっとGithubのどこのページにいても表示されているであろう「＋」ボタン - 「New Repository」からリポジトリを作成できます

Repository Nameはローカルで管理しているものと一致している必要はありません。

公開範囲の「Public」「Private」設定が**デフォではPublicになっている**ことに注意してください。

今回は「Initialize this repository with a README」はチェックを外した状態で大丈夫です。`.gitignore`や`license`も今回はなし（`None`）にしておきましょう。

「Create repository」をクリックすると、さくっとリポジトリが作成されました。

![ss_2020-09-27_3_14_33-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/c85ab409-441f-e6e8-01bd-110135885e43.jpeg)

次のステップがこの画面にすべて書かれており今回の場合は「…or push an existing repository from the command line」の部分になるのですが、コマンドばかりでやさしくないです。

# プッシュしてみる→エラー
さて、ローカルマシン上にはローカルリポジトリ、Githubには同期先となるリモートリポジトリができました。

このローカルリポジトリの内容を、リモートリポジトリに同期することを**プッシュ**といいます。

コマンドは前述のとおりGithubのリポジトリのページに表記されていますので、app使用例を見ていきましょう。

## fork
サイドバーRemotesを右クリック - Add New Remotes

## sourcetree
リポジトリ画面の右上、設定 - リモート - 追加


これらで開くダイアログではリモートの名前とURLを入力できます。

リモートの名前とは今回のGithubにあたるリモートリポジトリをローカル側で管理上の通称として扱うようなものですが、多くの方はGithub公式のおすすめ通り、originとしています。また他のチュートリアルなどを進める際にも困らないようにoriginとしておくのがおすすめですが、これが任意で決められるものであることは留意しましょう。

URLにさきほどのGithubのページに表示されていたURLを入力すれば登録ができます。今回はせっかくSSHの設定をしたので、SSH URLのほうを使いましょう。下記のような見慣れた形式のURLを見つけましょう。

```
git@github.com:account/git-test-prj.git
```

登録が完了したら、プッシュボタンを押してみましょう。

プッシュ画面にて対象のブランチを**master**にしてプッシュ。ブランチとかmasterとかを詳しく知りたい場合はおググりくださいませ。今は「masterと呼ばれる管理上の束なりを指定してリモートリポジトリに同期した」という感じのふわっとした認識で大丈夫です。

エラーが表示されなければばっちりなのですが、この手順だと確実にエラーになります。

# SSHでエラーでるやん？→SSHの便利機能

さてなぜエラーが出たのでしょう。上記で登録したURLと最初にSSHでgithubにSSH接続したURLを見比べて考えてみてください。

appを使っていても内部的には登録された内容に基づいてコマンドを実行しているのと同じです。そして登録されたURLがSSH URLの場合はSSHコマンドを用いているのと同じと考えましょう。
```
git@github.com:account/git-test-prj.git         //←これをとして登録したので
ssh -T git@github.com:account/git-test-prj.git  //←実態はこうなっているイメージ

ssh -T git@github.com -i ~/.ssh/id_rsa_github_account  //先程githubに接続成功したコマンド
```
少し足りないですね。

appで提供されているインターフェイスに合わせて、URLだけでSSHアクセスができることを目指すとすると、それはつまり、
```
ssh -T git@github.com
```
でSSH接続できること、となります。

先ほどコマンドでSSHした際のURLと違うのは`-i`オプションがないことですね。なので、これを省略できれば良いということになります。

このSSHコマンドには「あらかじめ設定しておけば特定のホストに対する接続の際にオプションを省ける」という便利な機能があります。

## ~/.ssh/config ファイル
この設定は先ほどの`.ssh`ディレクトリに`config`という拡張子なしのファイルを作成することで可能になります。Macにはこの設定のための[App](https://www.hejki.org/ssheditor/)がありますが、簡単な内容なので手動で作成しちゃいましょう。

```
cd ~/.ssh/
vi config
```

以下の内容を書き込み。viの使い方は近くにいるVimmerに聞くかおググりくださいませ。もしくは**config**というファイルを**.ssh**ディレクトリに作成しテキストエディタで書き込んでもOKです。（が、この際viの最低限の扱いもできるようになっておいていいと思います。qiitaにはviの優良記事がたくさんありますよ！）

```
Host github.com
  User git
  HostName github.com
  IdentityFile ~/.ssh/id_rsa_github_account
  IdentitiesOnly yes
  RequestTTY no
```

IdentityFileのところが、`-i`と同義ですね。

元のコマンドと見比べるとわかりやすいです。
```
ssh -T git@github.com -i ~/.ssh/id_rsa_github_account
```

これで晴れて下記コマンドでアクセスできるようになったかと思います。

```
ssh -T git@github.com
```

上の方に記述した**Hi!**のメッセージが出ればOKです。鍵も持たずアクセスできるとは、顔パス気分ですね。

勘の良い方はお気づきかもしれませんが、下記でも接続できるようになっています。
```
ssh github.com
```
便利ですね、`.ssh/config`。
ちなみに、`Host`のところを`github`にしたら、下記でアクセスできます。
```
ssh github
```
コマンドベースでGithubを使うならこちらのほうが楽でしょう。

## クローンもプッシュもSSHでできる！

ということで、リモート設定にGithubのSSH URLを指定してプッシュしてみましょう。

Githubのリポジトリページにいまプッシュした内容が反映されていればOKです。
エラーが出たらしっかり読んでみましょう。出るとしたら鍵周りか、リポジトリの状態あたりではないでしょうか。

# （余談）クローンから
さて、自分が管理するプロジェクトならば前述の手順でプロジェクトが開始できますが、業務などではすでに存在しているプロジェクトをもとに自身が手を入れていくことが圧倒的に多いでしょう。

そのような既存のプロジェクトを自身のマシンにコピーすることをクローンといいます。

## どう違う？
githubをはじめgitのホスティングサービスでは、リポジトリのソースコードをクローンするために`https url`と`ssh url`を提供してくれています。クローンのコマンドは

```
git clone URL
```

という感じになります。
プライベートリポジトリの場合、このコマンドを実行するとユーザー名とパスワードを求められるかと思います。

プッシュする際にもユーザー名とパスワードの入力が必要になります。

この手間を省くため、ここまでの手順で鍵ファイルを用いたSSHによる接続が可能になっていればSSH urlを用いてgithub上のgitリポジトリをパスワード認証なしで操作することができますね。

適当に公開されているリポジトリでもよいのですが、ここまで進めてくださっている場合は自分の作ったリモートリポジトリが存在しているので、それを使いましょう。

ということで、先ほど作ったローカルマシン上のプロジェクトディレクトリを削除しちゃいましょう。ちゃんと変更した内容をコミットしプッシュ出来ていれば、その全てはすでにgithub上に同期されています。何も怖くないです！

## いざ

sourcetreeやforkでは、既にGithub上にリモートリポジトリが存在している場合、クローンするのに必要なのは下記の情報です

- Repository Url（リモートリポジトリのURL。今回はGithub。）
- Parent Folder（そのリポジトリをクローン（保存）するフォルダー）
- Name（管理用の名前）

リモートリポジトリのURLはGithubのリポジトリ画面の右上`Code`ボタンから取得できます。

![ss_2020-09-27_3_09_46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/4fa52f9f-5c05-b62b-1e3e-23e7ffe1b390.jpeg)

sshのconfigの設定が済んでいればこの設定でクローンができるので、あとは、上記同様クローンしたディレクトリにてファイル変更を行いコミットしプッシュする流れでリモートリポジトリを変更することが出来ます。

実際の案件でもだいたいこの流れです。SSHキーを登録済みのアカウントを案件のリポジトリに招待してもらう形であれば、即クローン可能です。

# （余談）複数のアカウントの場合
さて、なにか事情があり、Githubアカウントが複数あり扱うリポジトリがそれぞれに属している場合、この手順を進めると困ったことになることに気が付くかと思います。

現在は、id_rsa_github_accountの鍵を用いてgithub.comへのアクセスを行います！と設定されているので新しいアカウント用に作成した鍵が使えないですね。理由は今までの流れをよく読み解くとわかります。

## 解決策
`~/.ssh/config`ファイルでgithubへの接続を複数定義します。

原因としては、Githubの仕様で「SSH接続時は同じ`git`というユーザー名を用いて、鍵だけで接続先アカウントを区別していること」です。
現在は`github.com`への接続はすべて同じ設定（同じ鍵を用いる状態）が適用されるようになっています。これを疑似的に`github-user1.com`と`github-user2.com`への接続という形に分けてしまいます。

```
Host github-user1.com
  User git
  HostName github.com
  IdentityFile ~/.ssh/id_rsa_github_user1
  IdentitiesOnly yes
  
Host github-user2.com
  User git
  HostName github.com
  IdentityFile ~/.ssh/id_rsa_github_user2
  IdentitiesOnly yes
```

こうすることで、`github-user1.com`へのSSHアクセスと`github-user2.com`へのSSHアクセスは区別され、別々の設定（鍵）が適用されますが接続先はどちらも`github.com`です。（このHostの命名は自由で、`gh-1`などでも大丈夫です。）

少し不思議な感じがするかもしれませんが、こんな感じになります。

```
$ ssh -T git@github-user1.com
Hi user1! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

$ ssh -T git@github-user2.com
Hi user2! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.
```

なので、接続先となるリモートURLの変更が必要になります。適宜変更しましょう。
リモートリポジトリのURLはこのようになります。

```
git@github-user1.com:account/git-test-prj.git
```
うまくいけばフェッチ・プル・プッシュなどが行えるかと思います。

少しややこしいですが、いくつかのリポジトリを扱いはじめるとすぐに慣れると思います。
ばんばんGithubにリポジトリを作って実験してみましょう。

# まとめ

SSH＋Git周りで扱いはじめの頃に「まずどうしたらいいんだろう」と悩んでしまう辺りをざーっと書いてみました。盛りだくさんになりましたが、ローカルでリポジトリを作る、クローンする、Githubにリポジトリを作る、リモートの設定を行うなど一通り出来て、sshのconfigを作成しsshを試すなど、これらを一通り成功させておくといざという時に困ることがなくなるでしょう。これらはgithub, gitlab, bitbucket, backlogなどプラットフォームをまたいでも（それぞれ機能の呼称が変わることがあっても）gitという仕組みの上になりたっているので概念は基本的に同じです。

そして、実際の現場ではブランチの扱い方やコミットの流れ、プルリクエストのルールなど所謂ローカルルールに則って業務を行うことになります。それは現場に入ってから・案件にアサインされてから共有されたドキュメントを読んだり前任者に確認して学ぶことになるでしょう。その前準備として、スムーズに業務にはいっていけるように、これらの基本をしっかり身につけておきましょう。

gitの様々な機能を使いこなすためにハードルとなるコマンドの多さも、各種appを使うことで簡単に乗り越えられますので、機能を知るためにも一つでもいいのでappを使いこなせるようになっておきましょう。逆に基礎的なコマンドを覚えることも強い武器になり得ます。`git log`や`git status`などは誰でも使えるべきだと個人的には考えています。（これらの基礎的なオプションを覚えておくだけで守備範囲がまた爆広がりするかもしれません）

本稿の最も基本の部分を押さえられたら、それに続くたくさん用意されているGitの便利機能にチャレンジしてみましょう。Gitは共同作業のための仕組みだということを忘れず、少人数やひとりでのプロジェクトでも積極的に活用し大規模プロジェクトにアサインされた時のための準備をしておくのが大事です。またgithubはOSSのためのプラットフォームでもあります。そこにプッシュ出来たということは、世界中のエンジニアとつながることができる第一歩を踏み出せたということを意味します。どんどん活かしていきましょう。