GitHubが落ちてても慌てずに済む、SSHとGitだけでのPush/Pull

<!-- GitHubが落ちてても慌てずに済む、SSHとGitだけでのPush/Pull -->

[Git Advent Calendar](http://qiita.com/advent-calendar/2016/git)をご覧の皆様、初めまして。Piroといいます。普段はJavaScriptやRubyでのソフトウェア開発やFirefoxの法人向け技術サポートなどをしつつ、[日経Linux誌][日経Linux]で[シス管系女子][]という連載マンガを描かせて頂いております。

今日の記事では、「SSHって何？」や「SSHは知ってるし時々使うけど、普段そんなに使う機会は無い」くらいのレベルの方を対象に、SSHとGitの組み合わせだけでこんな事もできるんですよ！という事をご紹介します。アドベントカレンダー的には最後の方の日なのに初心者向けの話で恐縮ですが、まあせっかくなのでおつきあい下さい。

## GitHubが落ちて困った！

日頃Twitterを見ていると、GitHubのサービスが停止する度に阿鼻叫喚の地獄絵図が繰り広げられている印象があります。

「デプロイしたいプロダクトの依存ライブラリがGitHubにあるのでデプロイできない」とか、「GitHub上のIssueでタスク管理をしているのでタスクを確認できない」とか、そういう事については確かにどうしようもないです。

が、単に「中央リポジトリがGitHubにあるせいでPushもPullもできない」という話なら、わざわざ自分でGitLabを立てたりBitBuckets等に引っ越したりしなくても、*お互いのコンピューターやあるいはどこかのサーバーにSSH接続さえできれば充分*だったりします。

## SSH越しにお互いにPullしあってみよう

筆者が東京に来てすぐの頃、会社の事務所のインターネット回線がまだ不通なせいで、メンバーみんながウィルコムの回線1本にぶら下がって帯域をシェアするという事をしていました。そんな状況では、とてもじゃないですがインターネット越しの中央リポジトリの利用なんて無理でした。GitHubが落ちた!という時に状況としては似ています。

こういう状況でも、幸いなことに我々はお互いの作業の成果を共有しながら開発を進めらました。何故かというと、*各人の作業環境でsshdを立てて、お互いのPCにリモートログインし合うことができたから*です。

### SSHって？

SSHは「Secure Shell」の略で、ネットワーク越しに別のコンピュータに接続してログインし、主にコマンド操作でそのコンピュータをリモート操作するという仕組みです。主にサーバーを操作するために使われる事が多いです。

とはいえサーバー操作の専用の物というわけではなく、手元のPCにSSHサーバーをインストールして起動しておけば、別のPCからあなたの手元のPCにログインしてリモート操作してもらうということもできます。

### SSHクライアントの入れ方

Webページを見るのにWebブラウザが必要なように、SSHで他のコンピュータをリモート操作するには*SSHクライアント*というソフトウェアが必要になります。

 * Windows用のSSHクライアントは[Tera Term](https://ja.osdn.net/projects/ttssh2/ "Tera Term (テラターム) プロジェクト日本語トップページ - OSDN")が有名ですが、これはGUIから起動して他のコンピュータを操作することに特化しています。今回は手元のPC上での操作が必要なので、[Git for Windows](https://git-for-windows.github.io/)を使うことを想定します。これによりインストールされる「Git Bash」を起動して`ssh`コマンドを実行すれば、SSHクライアントを起動できます。
 * macOS（OS X）は、初期状態でSSHクライアントがインストールされています。「Terminal」を起動して`ssh`コマンドを実行すれば、SSHクライアントを起動できます。
 * Linuxの場合、`ssh`コマンドは初期状態で利用できる場合が多いのですが、もし入っていない場合は「GNOME端末」あたりを起動して`sudo apt insntall openssh`（Debian系ディストリビューション）や`yum install openssh`、`dnf install openssh`などとしてインストールします。`ssh`コマンドを実行すれば、SSHクライアントを起動できます。

### SSHサーバー（sshd）の入れ方

Webページを公開するのにApacheなどのサーバーソフトウェアが必要なように、SSHで他のコンピュータからのリモート操作を受け付けるには*SSHサーバー（SSHデーモン、あるいはsshd）*というソフトウェアが必要になります。

 * Windows用には[Microsoftが開発者向けにOpenSSHを提供している](http://dev.classmethod.jp/cloud/aws/aws-windows-sshd/)ようです。残念ながら筆者はWindowsでsshdを立てたことがないので、詳しくはリンク先の記事を参照して下さい（すみません……）。
 * macOS（OS X）の場合、初期状態でsshdがインストールされています。「システム環境設定」→「共有」→「リモートログイン」にチェックを入れると、それだけでsshdが起動した状態になります。
 * Linuxの場合、まず`sudo apt insntall openssh-server`（Debian系ディストリビューション）や`yum install openssh-server`、`dnf install openssh-server`などとしてsshdをインストールします。インストールできたら、systemdが使われている環境（CentOS 7など）では`sudo systemctl start sshd.service`、Initスクリプトが使われている環境では`sudo service ssh start`とすればsshdが起動します。

リモート操作を受け付けるようにするという性質上、sshdの運用には色々と注意が必要です。一般的には、*管理者ユーザ（root）ではログインできないようにしたり、脆弱なパスワード認証ではなく安全な公開鍵認証のみを使うようにしたり*といった形で、安全側に倒した設定で運用するのが定番です。詳しいことは「sshd 設定」や「SSH サーバー 設定」などのキーワードで検索してみて下さい。ここではとりあえず「信頼できる人しかいない」社内のあるいは部署内のネットワーク上でだけ使う想定で、ガバガバ設定のまま使うことにします。（ノートPCで外出時にも使うという場合には、きちんと設定できるまでは外では停止しておきましょう。macOSの場合は設定を無効にし、Linuxの場合はサーバーを起動するためのコマンドの`start`の部分を`stop`にして実行してください。）

### Gitの入れ方

もちろんGitもインストールが必要です。GUIのGitクライアントを使っている場合でもこの記事で解説するようなことはできるはずですが、実際のやり方はクライアントに依存するため、この記事では一律に`git`コマンドを使う方法を解説します。

 * Windows用のGitクライアントにもいくつか種類がありますが、ここでは前述した[Git for Windows](https://git-for-windows.github.io/)を使うことを想定します。「Git Bash」を起動して`git`コマンドを実行すれば、Gitリポジトリをコマンドで操作できます。
 * macOSの場合、[XcodeのCommand Line Toolsをインストールする](http://qiita.com/marmot1123/items/688adc739eacf67ddb7d)とGitも利用できるようになります。インストール完了後は、「Terminal」を起動して`git`コマンドを実行すれば、Gitリポジトリをコマンドで操作できます。
 * Linuxの場合、`sudo apt insntall git`（Debian系ディストリビューション）や`yum install git`、`dnf install git`などとしてGitをインストールします。インストール後は`git`コマンドでGitリポジトリを操作できるようになります。


### SSH越しにPull

ここでは例として、同じLANにある以下の2台のコンピュータ同士の間でSSH越しに直接Pullする場合の手順を解説します。

 * Pullする側（自分）
   * Windows PC
   * IPアドレスは`192.168.1.10`。
   * ユーザー名は`mint`。
   * リポジトリはGit Bashで見た時の`/home/mint/ourrepo`の位置にclone済み。
   * 作業しているのは`master`ブランチ。
 * Pullされる側（相手）
   * Linux PC
   * IPアドレスは`192.168.1.20`。
   * リポジトリは`/var/ourrepo`の位置にclone済みで、所有者以外でも読めるようパーミッションを設定済み。

まず、Pullする人がPullされる人のPCにSSHでログインできるようになっている必要があります。Pullされる側のPCに`mint`ユーザーを作成するか、Pull操作専用のユーザーを作成しておきましょう。

SSHでログインできる状態になったら、Pullする側はGit Bash（macOSならTerminal、LinuxならGNOME端末）で以下のように`git pull`を実行しますす。

~~~bash
$ git pull ssh://mint@192.168.1.20:22/var/ourrepo master
█
~~~

普通だとリモートリポジトリの位置は`git pull origin master`とか`git pull https://github.com/****/*****.git master`とか`git pull git@github.com:****/*****.git master`といった形で指定しますが、SSHでログインできる先のコンピューター上のリポジトリは`ssh://(ログインに使うユーザー名)@(ホスト名またはIPアドレス):(sshdが接続を受けているポート番号)(リポジトリのフルパス)`という書き方で指定します。

すると、Gitが内部的にSSHクライアントを起動して相手のPCにSSHで接続し、相手の側のリポジトリに加えられた変更を`fetch`してくれます。やりましたね！

なお、sshdのポート番号が既定の22番である場合は、省略記法として以下のような書き方もできます。

~~~bash
$ git pull mint@192.168.1.20:/var/ourrepo master
█
~~~

おや、どこかで見たような形ですね。実はGitHubでよく見る`git@github.com:****/*****.git`というリモートリポジトリの指定は、`git`という名前のユーザとしてSSH接続する指定だったのでした。




## SSH越しにPushできる共有リポジトリを作ってみよう

PullができるならPushもしたくなりますよね。しかし、単純に以下のようにするとエラーになってしまいます。

~~~bash
$ git push mint@192.168.1.20:/var/ourrepo master
█
~~~

これは何故かというと、Pushしようとした先が通常のGitリポジトリだからです。Pushを受け付けるためには、*bareリポジトリ*という物を用意しないといけません。

bareリポジトリは作業ファイルを伴わない、純粋に情報を溜め込む事に特化したリポジトリです。`git clone`する時に`--bare`というオプションを付け、Clone先のディレクトリ名に`.git`を付けると、bareリポジトリを作る事ができます。例えば以下の要領です。

~~~bash
$ cd /var/
$ git clone --bare ./ourrepo ./ourrepo.git
█
~~~

ということで、Pushを受け付けたい側のPCにはあらかじめbareリポジトリを用意しておきましょう。

先程と同様、同じLANにある以下の2台のコンピュータ同士の間でSSH越しに直接Pushする場合を例として解説します。

 * Pushする側（自分）
   * Windows PC
   * IPアドレスは`192.168.1.10`。
   * ユーザー名は`mint`。
   * リポジトリはGit Bashで見た時の`/home/mint/ourrepo`の位置にclone済み。
   * 作業しているのは`master`ブランチ。
 * Pushされる側（相手）
   * Linux PC
   * IPアドレスは`192.168.1.20`。
   * `mint`ユーザでSSHログイン可能。
   * bareリポジトリは`/var/ourrepo.git`の位置にあり、所有者以外でも読み書きできるようパーミッションを設定済み。

とはいえ手順としては単純で、リモートリポジトリの指定をbareリポジトリの方にするだけです。

~~~bash
$ git push ssh://mint@192.168.1.20:22/var/ourrepo.git master
█
~~~

省略記法を使えばこうですね。

~~~bash
$ git push mint@192.168.1.20:/var/ourrepo.git master
█
~~~

これもまた、なんだか見慣れた形です。これを見ると分かるとおり、GitHubは`git`という名前のユーザでSSH接続して、用意しておいたbareリポジトリを相手にPushやPullを行っているわけです。




## SSHとコマンド操作を恐れなければ、世界は思ったより広くて自由！

ということで、わざわざGitLabを立てたりしなくてもSSHさえ使えるならコンピュータ同士の間で直接PushやPullができる、というお話でした。

これを応用すると、*Gitを使った簡単なデプロイ*が可能になります。実際に、筆者は自分の個人Webサイトの静的なソースを自宅にあるファイルサーバー上にGitリポジトリの形で置いており、作業用PCとレンタルサーバー上の公開ディレクトリの2箇所にリポジトリをCloneしています。作業環境でソースに手を入れた場合はそれを自宅サーバー上のリポジトリにPushして、その後レンタルサーバー上のリポジトリでPullするだけでもうデプロイ完了です。

この運用には*サーバー上で行った緊急の修正を共有しやすい*という利点もあります。サーバー上で急遽ミスを修正したり暫定的な対応を取ったりした後は、`git push`すれば自宅サーバーのリポジトリに変更が反映されます。後はまたそれを作業環境の方でPullするだけで、緊急で行った修正の内容を損なうことなく次の作業ができるというわけです。

また、別の応用の仕方として、仮想マシンの中と外でのファイルのやり取りに使うという事もできます。つい先日、とあるRailsアプリの検証用実行環境としてVagrantで管理されるVirtualBox VMを用意したのですが、そのRailsアプリはデプロイ方法が独特で`vagrant`ユーザではない特定の名前のユーザのhome以下にファイルを設置する必要があり、「`/vagrant`にマウントされるディレクトリ以下にファイルを置いて、VM外でファイルを編集してVM内で即動作を確認」ということができませんでした。そこで、`vagrant ssh`によるSSHポート転送でトンネルを掘り、そこを通す形で特定ユーザのホーム以下に置かれたリポジトリとVM外のリポジトリの間でPullし合って、細かい変更を随時反映するという使い方をしました。

端末を使ったSSH越しのリモート操作は、勝手が掴めていないと目隠しをしてスイカ割りをするような不安やもどかしさがあり、つい苦手意識を持って避けてしまいがちでしょう。でも、「自分がコマンドを実行したとき、この端末の黒い画面の向こうで一体何が起こっているのか」をきちんと把握できるようになれば、そこにはお仕着せのツール越しに見ていたのとは全く違う自由な世界が広がってますよ！
![thumbsup.png](https://qiita-image-store.s3.amazonaws.com/0/61387/102129cc-ff07-40b7-f862-fc4bed52fb9f.png)

ところで、自分は2011年から[日経Linux][]誌上で「シス管系女子」というケーススタディ形式の解説マンガ記事を連載させて頂いています。主に「SSHでサーバーをリモート操作する」というシチュエーションでの「あーこういうのあるある」事例を取り上げて、その時何が起こっているのか・どうすれば悩みを解決できるのかを絵解き解説するという内容です。

筆者自身、元々クライアントサイドの開発が主な活動分野だったため、サーバ操作は非常に苦手だったのですが、業務の中でWebサービスの運用に関わる中で少しずつ要領が分かってきたという経緯がありました。本連載にはその経験がふんだんにフィードバックされていますので、普通に体系的にコマンド操作のことを学ぼうとして挫折した方にこそオススメな内容となっています。もし良かったら、お近くの大きめの書店で[シス管系女子][]の本や[掲載誌][日経Linux]を手に取ってチラ見して頂けましたら幸いです。

あと、[Twitterのみんとちゃんbotアカウント][みんとちゃんbot]でイラスト[^イラスト]や本編に入りきらなかった小ネタを流したり、Webサイトの方にも[連載や本では扱わなかったもっと基礎的な話の特別編](http://system-admin-girl.com/comic/#begins)を置いていたりします。[「シス管系女子」をテーマにしたAdvent Calendar](http://www.adventar.org/calendars/1692)も公開中です。

[^本稿執筆時点]: 2016年12月24日現在。
[^イラスト]: [これまでのイラスト一覧](http://system-admin-girl.com/comic/#illust)

[マンガでわかるGit](https://codeiq.jp/magazine/category/git-ai/)でGitの仕組みや使い方を覚えた方は、その勢いでLinuxのコマンド操作もマンガで覚えてみませんか？

ということで、Git以外の話ばかりでしたがGit Advent Calendarの24日目でした。最後の25日目は[liubinさん](http://qiita.com/liubin)によるお話です。お楽しみに！

[シス管系女子]:http://system-admin-girl.com/
[みんとちゃんbot]:https://twitter.com/sysadgirl_mint
[日経Linux]:http://itpro.nikkeibp.co.jp/linux/