今度こそ挫折しない git 入門 第1回

こんにちは、バカンのソフトウェアエンジニアの垣野内です。
この記事は[バカン Advent Calendar 2019](https://qiita.com/advent-calendar/2019/vacan)の2日目の投稿です。
プログラミング初心者向けの記事を1つお届けしようと思います。
(全2回。 2回目はこちら→ [今度こそ挫折しない git 入門 第2回](https://qiita.com/kakinouchi/items/77632d1bcc19bff4b588))

# なぜ git の記事か
自分自身、初心者だった時に git がなかなか理解できなかった記憶があり、このような解説があればもう少し習得が簡単だったかもしれないなーと思ったからです。
なので、**git に入門したい・git に入門しようと思ったけど挫折したことがある**という方が想定読者です。
この記事を読んで git の基本的なことを理解できれば、適宜ググることができるかと思います。

類書にない点/工夫した点は、以下の3点です：

    1. コマンドラインで git のコマンドを懇切丁寧に解説にした
    2. git のコマンドの話と git の概念的な話を明確に分離しつつ、それらの対応を意識的に書いた
    3. git の入門のゴールを2段階に分けた(個人で使うシーンとチームで使うシーン)

コマンドラインでの学習をおすすめするのは、git の操作に集中できるからです。
(はじめからGUIツールでやってしまうと、何がgit の操作で何がそのツールの便利機能なのかという区別がつきにくいのではないかと思います)[^1]

”黒い画面”を怖がらず、ぜひ見よう見まねで try してみていただければと思います！

それでは本題です！
まわりくどい説明が嫌いな方は [git における4つの場所と5つのアクション](https://qiita.com/kakinouchi/items/be54d21adcac1debc0c0#git-%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B4%E3%81%A4%E3%81%AE%E5%A0%B4%E6%89%80%E3%81%A85%E3%81%A4%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B33) に飛んでください！

# そもそもなぜバージョン管理をするのか
そもそもなぜバージョン管理をするのかというモチベーションを考えながら、ファイル名に日付やバージョン( 画面仕様書_20191201.xlsx や 来期売上目標_v1.0.1.ppt など)を書いたり、変更履歴のシートを作ったりするスタイルのバージョン管理(以下本稿では「手動スタイル」と呼ぶことにします)だとどのような問題点が起こってくるのかを見ていきます。

(もちろん、手動スタイルで事足りればそれでよいのです)

 - 変更履歴を調べたい  
   一人で作業している時でも過去に自分の変更を調べたくなる時はあるでしょうし、チームで同じファイルを触っている時は、いつの間にかファイルが変わっていて、誰がどのような意図で変更したのかを調べたくなる時もあるでしょう。開発の文脈ではバグ調査に便利ですね。
これを手動スタイルでやろうと思うと、日付だけでは情報が足りませんし、かなり骨の折れる作業になることが予想されるでしょう。
 - 過去のバージョンに戻りたい  
   変更を加えてみたものの、やっぱり過去のやつに戻したくなる時があるかと思います。直前の状態に戻せばいいだけであれば手動スタイルでも全く問題ないですが、さらにさかのぼりつつ特定の変更は消したくない場合などを考えると、少し面倒になってきそうですね。
 - ファイル同士の整合性を保ちたい  
   あるフォルダ[^2] の中にファイルAとファイルBがあって、これらのファイルに関係性がある場合を想像してみてください。例えば、仕様書の概要をファイルAとして書き、詳細はファイルBに譲る時などです。この時、ファイルAとファイルBのバージョンには一定の制約が出てくるはずです。ファイルAがバージョンXの時はファイルBはバージョンYでないと困る; つまり、どちらかが古いと困るわけですね。
git ではこのような状況を解決するために、フォルダごとバージョンを管理します。
 - 共同作業をしたい  
   あるファイルのとあるバージョン(例えば example_v1.0.1.txt だとしましょう)対して、AさんとBさんが同時にかつ別の変更を加えたい時がしばしばあります。同時編集を許可することによって解決するのがよくあるやり方ですが、互いの作業を気にしながらやることになりますね。
git ではこの動機に対して(軽量な)ブランチという考え方で対処します。ブランチとは「枝分かれする」という気持ちで、[第二回](https://qiita.com/kakinouchi/items/77632d1bcc19bff4b588)で詳しくみていきますが、喩えるならパラレルワールドを作るようなイメージです。  
(とはいえ互いの作業を全く気にしなくてよくなるわけではありませんが)

# git における4つの場所と5つのアクション[^3]
ここでは 概念的な話とともに git の用語を解説します。一読してわからなくても、[コマンド練習その1](https://qiita.com/kakinouchi/items/be54d21adcac1debc0c0#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E7%B7%B4%E7%BF%92%E3%81%9D%E3%81%AE1)のところで意味がわかるかもしれません。往復しながら読んでみてください！

git ではバージョン管理したいフォルダをまるごと監視対象にします。この時、フォルダの中は以下の図のように3つの場所にわかれます。

- リポジトリ  
   バージョン管理をしている実体です。データベースと思ってもよいでしょう。
- ステージングエリア  
  保存する単位を作るところです
- 作業ディレクトリ(ワーキングディレクトリとも)  
  バージョン管理対象のファイル/フォルダです。基本的にここしか直接触りません。
  (ステージングエリアやリポジトリに対してはコマンドを通して指示するのみ)

作業ディレクトリでなにか変更をしたら、その変更をステージングエリアに一度うつします。これを「ステージングエリアに add する」などと言ったりします。
次に、ステージングエリアにあるものをリポジトリにうつすことで、その変更が記録されます。これを「コミットする」と言い、この時にリポジトリにできた変更の単位を「コミット」と言います。
**「変更して、add して、commit する」** という流れです。
(次節でコマンドの練習をするとこの流れがよりイメージができるかと思います)

このステージングエリアがあることにより、ファイル同士の整合性を取ったままバージョン管理をすることができます。
例えば、ファイルAの変更とファイルBの変更を一つの変更の単位としてコミットすることができるというわけです。

![git_repo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/d2dddc8d-0017-9ae8-ead3-910b24084945.png)

さて、今の説明は個人のPCでの作業の流れでした。この変更を他の人と共有するにはどうすればいいでしょうか？ 
git では、以下の図のようにリモートリポジトリというものを作ります。対して、個人個人のPCの中にあるリポジトリはローカルリポジトリとよばれます。(つまり、上の図のリポジトリは正確に言えばローカルリポジトリです)
ローカルリポジトリの変更をリモートリポジトリに反映することを「pushする」と言い、逆に、リモートリポジトリの最新の状態をローカルリポジトリに反映させることを「fetchする」と言います。
(fetch とは「引っ張ってくる」という気持ちです)
なのでリモートリポジトリまで含めると、**「変更して、add して、commit して、pushする(リモートが変更されてたら適宜fetchする)」** という流れになります。


![git_concept.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/18521aa2-4835-3f70-f60f-3e76bb5c98c8.png)





また、ローカルリポジトリがまだない時は、リモートリポジトリをまるっと持ってきます。
これを「clone する」と言います。
一度 clone したら先ほどの説明のとおり、**「変更して、add して、commit して、pushする(リモートが変更されてたら適宜fetchする)」** という流れです。

非常におおざっぱですが、以上が git の考え方と基本的な用語の説明です。
(繰り返しますが次節でコマンドの練習をするとよりしっくりくるはずです)
もう一度用語を列挙しておきます：

  - リモートリポジトリ
  - ローカルリポジトリ
  - ステージングエリア
  - 作業ディレクトリ/ワーキングディレクトリ
  - clone
  - add
  - commit(名詞と動詞)
  - push
  - fetch

# コマンド練習その1
概念的なところがなんとなく理解できたところでコマンドの練習にうつっていきたいと思います！
git をインストールした後、以下読み進めてください。

まずは適当なフォルダを作りましょう。ここでは gittest というフォルダを作りました。

<img width="882" alt="command1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/c3c3e98f-3c21-a392-c7c1-fca32be5f225.png">

次にMac ならターミナルを、Windows であればコマンドプロンプトあるいはGit Bash を開いてください。[^4] そして、今作った gittest というフォルダに移動してください。(Mac / Windows ともに cd で移動できます)


<img width="562" alt="command2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/535c9759-c074-03a2-8996-0f534dfa20d7.png">


最初に `git init` というコマンドを叩いてみましょう。
  このコマンドを実行すると、そのフォルダが git の監視対象となります。
  実はこの時隠しフォルダとして `.git` フォルダが生成されており、この中に上述したリポジトリとステージングエリアがあります。逆に言うと、この隠しフォルダを消してしまえば再びただのフォルダになります。

<img width="669" alt="command3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/0714a32c-df4f-0077-2e36-5f0cf91ce5bc.png">

<img width="882" alt="command4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/669ca7a7-8c39-bf50-9808-82bd093bcf9a.png">



次に、`git status` というコマンドを叩いてみましょう。git として現在どういう状態にあるのかを表示してくれるコマンドです。情報を教えてくれるだけで何も破壊しないので、困ったらこのコマンドを叩いてみるとよいでしょう。
ここではまだ何もコミットをしていないにで、「No commits yet」と言われるだけかと思います。

<img width="708" alt="command5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/f057a72b-5aad-8635-76b6-43b75d9e913f.png">



それでは、なにかファイルを加えてみましょう。ここでは test1.txt というファイルに「git first test」と書いて保存してみました。

<img width="882" alt="command6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/1aaa0ab3-ebb7-4a47-1599-b457246d7a1f.png">

![command7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/7f15c454-2fa5-3032-5fa8-ec37c38958cd.png)



もう一度 `git status` を叩いてみましょう。
  今度は、「No commits yet」に加えて、「Untracked files:test1.txt」と言われたかと思います。そしてカッコ書きで、「use "git add <file>..." to include in what will be committed」と書いてあるかと思います。「コミットするものに入れたかったら `git add <ファイル名>`とコマンドを打ってね」と言っています。

<img width="699" alt="command8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/75808241-b35d-e2b3-6c19-1ae8a5a7767a.png">



では git に言われたように `git add <ファイル名>` を叩いて、また `git status` をしてみましょう！
今度は、「Changes to be comitted: 」と表示されたかと思います。これが今ステージングエリアにあるものの一覧です。
`git add`によって、作業ディレクトリから、ステージングエリアにうつったということです。

<img width="715" alt="command9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/cd696af6-43a1-8915-50c5-d275135b27a5.png">

それではいよいよコミットです！ `git commit -m ”コミットメッセージ”` と打ってみましょう！コミットメッセージは、変更の意図を記録しておくものです。(`-m` をつけることでコミットメッセージをつけられます)
後から調査した時に、なぜこの変更を入れたのかをわかるようにしておくと便利です。ここではテストのためあまり真面目にやらず、`git commit -m "first commit"` としておきます。

以下のような表示がされていれば初のコミット成功です！おめでとうございます :tada::tada::tada: 
これであなたもgitに入門できました！
このコマンドで、ステージングエリアにあったものがローカルリポジトリにコミットされ、コミットとして記録されました！

<img width="770" alt="command10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/2374bc2a-188d-d382-4422-65b192344501.png">



ここでもう一度 `git status` をしてみましょう。「nothing to commit」つまり、「コミットするものはないですよ」となっているはずです。


<img width="768" alt="command11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/522c931d-87aa-2425-3187-42290aad8538.png">




コミットしたものを確認するにはどうすればいいでしょうか？そのためのコマンドが `git log` です。たたいてみましょう！
変更者(Author)、日付(Date)、変更理由(コミットコメント)が表示されましたね。
![command12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/36533f33-f911-45b6-c4e2-58c7838cc565.png)

**「変更して、add して、commit する」** という流れを掴んでいただけたでしょうか？
読者の練習としますが、先程のtest1.txtの中身を変更して、もう一度同じことをしてみてください。`git log` で以下のようにコミットが2つになっていれば成功です！

![command13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/2a19dcdb-7ea5-ead7-e339-7b2310ae4fce.png)

--- 

この節のおさらいです。以下のコマンドを身につけ、git の基本的な流れである **「変更して、add して、commit する」** を理解していただけたかと思います。
- `git init` (git リポジトリを作成します)
- `git status`  (git としての状態を確認できます)
- `git add <ファイル名>` (修正をステージングエリアにあげます)
- `git commit -m ”コミットメッセージ”` (ステージングエリアにあるものをリポジトリにコミットします)
- `git log` (コミットの履歴を確認できます)

# GitHub について
コマンド練習その1 ではローカルリポジトリのみの作業でした。
ところで、リモートリポジトリはどこにおくとよいのでしょうか？
実はこれはどこでもよいのです。どこか別のPCでもよいですし、サーバをレンタルしてそこに作っても構いません。
そこで便利なのが GitHub です。 GitHub は git リポジトリの”置き場所”を提供してくれるとともに、開発の文脈で言えばコードレビューなどが非常に便利なため、これをリモートリポジトリとして使うケースが多いです。
gitリポジトリの”置き場所”を提供するサービスのことを「gitのホスティングサービス」などと言ったりしますが、GitHub 以外にも、Bitbucket や GItLab などが有名です。チームによって何を使うか変わってくるでしょう。


GitHub も少し練習をしてみましょう！

まず、GitHub 上で git リポジトリを作ってみます。GitHub のアカウントを作ったら、右上の「New repository」というところをクリックし、Repository name に適当な名前(ここでは github_test としました)を入力し、「Initialize this repository with a README」にチェックを入れ(入れなくてもいいんですが、通常作るので)、「Create repository」ボタンをクリックします。
  (GUIで簡単にできますが、リモートリポジトリで `git init` しているということです)

<img width="1440" alt="github1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/76cba45a-54f0-4676-6f51-e1e232d66821.png">

<img width="1440" alt="github2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/0311a073-96de-dfae-531c-8299b6b251ff.png">

すると、作ったリポジトリの画面に移ると思うので、「Clone or download」のボタンをクリックし、URLの右のコピーボタンをクリックしてください。(ここでは SSH ではなく HTTPS を使うので初心者の方は注意してください)

<img width="1419" alt="github3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/3d60e4a4-02f5-ddf7-da68-ee50b5db9614.png">


再びターミナルに戻ります。さっきのディレクトリとは別のところに行き、`git clone <さっきコピーしたもの>`とコマンドを打ちます。

<img width="943" alt="github4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/f32c84ae-448b-b780-b84e-0a26b254880f.png">



すると、github_test というフォルダができるので、そこに移動します。`git status` と `git log`を叩いてみましょう。
コマンド練習その1の時と違い、git log で origin というものが出てくるようになりましたね。
これは、リモートリポジトリのことです。[^5] 
   
<img width="970" alt="github5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/35dd28f9-50af-3597-4faf-231f1bd162cf.png">


ではコマンド練習その1の時と同じように、**「変更して、add して、commit する」** をやってみましょう！以下のような log が作れたらOKです！

![github6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/d3ab4c00-892a-c04d-660c-5d6d2ed33947.png)


そして今度は push してみます。`git push origin master` と叩いてみましょう！
  以下のような表示が出ていれば成功です！
  これで、ローカルリポジトリの変更がリモートリポジトリに反映されました！

<img width="779" alt="github7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/e2a9969e-2d7d-816c-4108-d8244f25f54f.png">


先ほどの GitHub のリポジトリの画面に行ってみましょう！ローカルでの自分の修正が反映されているでしょうか？

最後に、もう一度 `git log` を見てみましょう。`git push` したので、リモートの状態がローカルの状態と一致していることはずです。

![github9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540893/6846f0da-356f-450d-4a97-e3ba74a971e0.png)


--- 

この節のおさらいです。GItHub を例に取って、リモートリポジトリを含めた git の流れ： **「変更して、add して、commit して、pushする」** を理解していただけたかと思います。

1人でバージョン管理をする場合は、ここまでだけでも十分と言ってよいでしょう。

# おわりに
git の使い方がなんとなくわかっていただけたでしょうか？
次回(アドベントカレンダーでやるかは未定ですが)はチームで使うシーンを想定しつつ、ブランチの話をしたいと思います。

それではよいお年を！！
明日はIoTの会社らしい記事です！お楽しみに！ :christmas_tree: 

# 参考文献
- [入門Git](https://www.amazon.co.jp/dp/4798023809) 絶版となってしまったようですが、個人的にはとても好きな本です。合う/合わないがとてもはっきりわかれる本だと思います。
- [ Git の仕組み (1) ](http://koseki.hatenablog.com/entry/2014/04/22/inside-git-1) この記事を読んで Git って面白いなと思ったのでした。ものごとの仕組みに興味のある方は、コマンドに慣れてきたころに読んでみると面白く読めると思います。
- [サルでもわかるGit入門](https://backlog.com/ja/git-tutorial/)
- https://twitter.com/098ra0209/status/1163424568544907265 最近 twitter で見つけたものです。ポップな絵とともに用語の整理ができてよいですね。

# 参考リンク
- [株式会社バカン（Vacan, Inc.）](https://www.vacancorp.com/)
- [バカン (Vacan) Advent Calendar 2019](https://qiita.com/advent-calendar/2019/vacan)

[^1]: プログラミングにしても、最初はIDEを使わずに軽量なエディタとターミナルで入門するとよいのではないかと思ってる派です。
[^2]: 初学者の方になじみやすいよう、本稿では(ディレクトリではなく)なるべくフォルダという言い方を選んでいます。
[^3]: この表現は、『スッキリわかる Java入門 実践編』におけるSVNの説明;「2つの場所と3つのアクション」というものを拝借し、git 版にしたものです。いい説明だなと思いました。
[^4]: 筆者は git bash 推しです。windows のコマンドを思い出すのが面倒くさいからですw
[^5]: 正確に言うと、リモートリポジトリの1つに origin という名前がつけられています。