2留でもわかるGit

#<i class="fa fa-pencil-square-o" aria-hidden="true"></i> はじめに
---
***みなさん、Git使ってますか？***

私は以前からGitを使用していました。しかし、先日バイト先でGitの講習会が開かれた際に講師として任命されたのですが全くもってGitについての説明ができない事態に陥り、「使える ≠ 教えることができる」ということに気づきました。教えることができないということはすなわち、理解をできていないということです。私に限らずGitコマンドを扱うことはできても概念を理解せずに使っているという人は大勢いるのではないでしょうか。(勘違いでしたら申し訳ございません)
自身の勉強も含めてこちらの記事を作成しましたので是非みなさまのGitの概念の理解の一助になればと思います。

##この記事の対象

* Gitを使ったことがない方
* Gitを使ったことがあるけど概念を理解していない方

##この記事のあらすじ
1. [VCSとは](http://qiita.com/oreo/items/dfa81d184811c2b9dab4#vcsとは)：Gitよりも更に大きな枠組であるVCSについての説明を挿入しました。こちらはなるべく「コミット」や「リポジトリ」等の単語を使用せずに作成しましたのでVCSとは何かご存知でない方は読んでいただければと思います。
2. [Gitとは](http://qiita.com/oreo/items/dfa81d184811c2b9dab4#gitとは)：本題のGitについての説明です。概念の説明を主としたいと考えているため、コマンドの解説ではなく用語解説を中心としました。

##参考にしたサイト
当記事は下記のサイトを参考に執筆しました。引用を多々含むまとめといった形になります。どれも大変素晴らしい資料ですのでお時間のある方は是非読んでいただければと思います。

* [Gitをはじめからていねいに](https://github.com/Shinpeim/introduction-to-git)
* [VCS入門](https://github.com/masaru-b-cl/introduction-to-vcs)
* [サルでもわかるGit入門](http://www.backlog.jp/git-guide/)

#<i class="fa fa-code-fork" aria-hidden="true"></i> VCSとは
---
VCSとは**Version Control System**（バージョン管理システム）の略称となります。
開発をしているなかで人間が引き起こしやすいミスを防ぎ、円滑にチームでの開発を進められるようにすることを目的で作られたファイルの変更履歴管理ソフトです。

##VCSの能力
###履歴を保存
「誰が」「いつ」「何を」したのかを記憶ではなく記録として残すことができるようになり、履歴を残せるようになると具体的に3つのことが可能となります。

1. **参照**：記録を元に誰がどんな変更を加えたか把握できる
2. **再現**：動かなくなった状態の前の状態に戻せる
3. **分岐**：複数のアプローチによって作業を進めることができる

###競合を防止
本来VCSがないと「後勝ち」が優先となり前に変更した人の変更内容は失われてしまいます。しかし、VCSを使うことで主に2つのことができるようになります。

1. 事前に競合を検知
2. 変更箇所を解析し、自身が行った変更内容と自動で統合

VCSがある世界では自分自身も他のメンバーも安心してハッピーな開発を行うことができます。

##VCSを導入しただけでは幸せになれない！？
例えツールを使っていても根底はチームでの協調作業です。メンバーが好き勝手動いていては上手く開発は進みません。

###よくない例
####1. 「とりあえず」反映している  

```markdown:メッセージ
20XX年8月3日：昼休み前のコミット
```
```markdown:メッセージ
20XX年10月21日：本日分の作業
```  
時間の区切りでコミットすることは複数の変更を一度に反映することであり、履歴を調べる作業は困難となってしまいます。

####2. 「どうやったか」を書いている

```markdown:メッセージ
20XX年9月12日：◯◯ファイルに◯◯メソッドを追加
```
どこをどう修正したのかは分かりますが変更した「理由」がわからないので履歴を調べる為の情報としては不十分です。

####3. 動かないものを反映

```markdown:メッセージ
20XX年3月15日：コンパイル失敗するけれど原因が分からないので一応反映
```

**最悪**。動かないものを本番環境で管理している為、個人の問題がチーム全体の問題に発展してしまいます。

####4. 複数の変更を同時に反映

```markdown:メッセージ
2015年11月1日：◯◯ファイルに△△処理と××機能を追加した。ついでに□□のバグを修正
```

複数の変更を一度に行うと履歴を調べるのが困難となります。

##それではどうするか？
VCSはルールと対になって初めてその真価を発揮します。最低限、作業フォルダーの内容を反映する際のルールを決めましょう。

* 「時間」ではなく「作業」の単位でコミットを行う
* 「どのように」ではなく、その作業を「何故」「何を」「何のために」行うかをメッセージに残す
* 動かない成果物はリポジトリに反映しない
* 一度に一つの変更だけ反映する

##VCSまとめ
VCSのVersion(バージョン、版)とは「ファイル単位の改定内容」を表すものではなく「**作業単位の変更内容**」を表しています。「一言で何をするのか表せる単位で作業を区切ってリポジトリに反映する」ことが重要であり一言で表せないときは小さな単位に分けて作業を行えないか考察をしましょう。

# <i class="fa fa-git" aria-hidden="true"></i> Gitとは
---
Gitとは数あるVCSの中の一つです。様々な機能がありますが一番の特徴は「**分散型VCS**」であるということでしょう。また、VCSには分散型VCSの他に「**集中型VCS**」というタイプも存在し、こちらはSubversionなどで採用されています。
Gitでは「**ワークツリー**」「**インデックス**」「**リポジトリ**」の3つのエリアで作業が行われます。

##集中型VCS
集中型VCSとは、プロジェクトの全ファイルが**一箇所**に (多くはサーバー上に) 存在するという考えに基づいています。プログラマーはこのファイルに変更を「コミット」することになります。
変更の「コミット」は、中央のサーバー上に記録され、その後、他のプログラマーはこの変更を見ることができます。また、変更を取得することも可能です。
![9cYrVEf72VDZfKgifbrlzzD4MZ3UYoz6bwhH4hMLin8.png](https://qiita-image-store.s3.amazonaws.com/0/48027/a0bac108-35d5-8d6a-1a28-74f390afc05b.png)

##分散型VCS
分散型VCSでは、プロジェクトファイルの全バージョンがサーバー上の「**リモートリポジトリ**」と自身のデバイス上の「**ローカルリポジトリ**」に保管されています。各開発者はリポジトリのコピーを「クローン」し、自身のデバイス上にそのプロジェクトの完全な履歴を持ちます。
![oreo02-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/48027/2af6f76b-dee0-1a40-aaa3-4dd2f4f70e9e.jpeg)



##用語解説
###ワークツリー
Gitの管理下に置かれた、ユーザー実際に作業をしているディレクトリのことをワークツリーと呼びます。

###インデックス（ステージ）
ファイルの一部の変更だけをインデックスに登録してコミットすることができます。ファイルをインデックスに登録することをステージングと呼びます。

###リポジトリ
リポジトリとはファイルやディレクトリの状態を記録する場所です。保存された状態は、内容の変更履歴として格納されています。また、Gitには2種類のリポジトリが存在します。

####1. リモートリポジトリ
専用のサーバに配置して複数人で共有するためのリポジトリです。

####2. ローカルリポジトリ
ユーザ一人ひとりが利用するために、自分の手元のマシン上に配置するリポジトリです。

###コミット
コミットとはファイルやディレクトリの追加・変更を、ローカルリポジトリに記録する作業のことです。
コミットを実行すると、リポジトリ内に前回コミットした時の状態から現在の状態までの差分を記録したコミットオブジェクト(リビジョン)が作成されます。

###プッシュ
ローカルリポジトリ内の変更履歴をリモートリポジトリにアップロードする作業をプッシュと呼びます。
プッシュを実行すると、リモートリポジトリ内の変更履歴がローカルリポジトリの変更履歴と同じ状態になります。

###プル
リモートリポジトリ内の変更履歴をローカルリポジトリにダウンロードする作業をプルと呼びます。
プルを実行するとフェッチ及びマージが行われます。

###フェッチ
フェッチを実行すると、リモートリポジトリの最新の履歴の取得だけを行うことができます。取得したコミットは、名前の無いブランチとして取り込まれます。

###ブランチ
ブランチとは、履歴の流れを分岐して記録していくためのものです。分岐したブランチは他のブランチの影響を受けないため、同じリポジトリ中で複数の変更を同時に進めていくことができます。

###チェックアウト
作業するブランチを切り替える作業のことをチェックアウトと呼びます。 チェックアウトを実行すると、まず移動先のブランチ内の最後のコミットの内容がワークツリーに展開されます。また、チェックアウト後に行ったコミットは、移動後のブランチに対して追加されるようになります。

###ブランチの統合
作業が完了したブランチは、最終的に統合ブランチに統合する必要があります。Gitでは特徴が異なる2種類の履歴を統合する手段が存在します。チームの運用方針に応じて使い分けましょう。
 
####1. マージ
変更内容の履歴はそのまま残るが、履歴が複雑になる。

####2. リベース
履歴がシンプルで直線的なわかりやすいものになるが、元のコミットから変更内容が変更される。
そのため、元のコミットを動かない状態にしてしまうことがある。
![oreo03-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/48027/878f6a79-6c93-ec3d-9010-9973bfcd8a74.jpeg)

#<i class="fa fa-pencil-square-o" aria-hidden="true"></i> おわりに
---
さて、いかがでしたでしょうか。
Gitを勉強した後にGitの扱い方に関する様々な記事を読んだのですが意外と間違った記述が多いことに気づき、身を以って「今、参考にしている記事が100%正しいとは限らない」ということを思い知らされました。
こちらの記事も不備がないように何度もチェックを行い、投稿をしましたが見落としている点や勉強不足により理解が誤っている点等の様々な不備が存在する可能性がございます。もし、記事を読んだ上でお気づきの点がございましたらコメント欄にコメントを残していただければと思いますのでよろしくお願い致します。ありがとうございました。

##追記 (2015.09.12)
2番目及び3番目の図の「ローカルリポジトリ」から「ワークツリー」への流れを修正しました。
マージ・リベースではなく正しくは「チェックアウト」となります。
(コメントをしてくださった@culageさん、ありがとうございます！)