Git入門(initからGitHubでPRを立てるところまで)

## はじめに
「gitってなにそれ？」という人も共同開発に必要なコマンドを試しに使ってみようというページです。

gitレポジトリの導入から、共同開発でgithubを利用する上で必要な操作、レポジトリに対してプルリクエストを送るところまでやってみたいと思います。

## 1.Git入門（ローカル環境にgitレポジトリを作る）
まずはローカル環境でgitを導入してみるところから始めます。

最初の章では

- init
- add
- commit
- status
- diff
- log

のgitコマンドを扱っていきます。

その前に、適当なディレクトリを作ってみましょう。

```
$ mkdir <PATH/dir name>
```

PATHの部分がなければ、暗黙的にカレントディレクトリ直下に新しいディレクトリが作成されます。

新しいディレクトリを作ったところで、カレントディレクトリを新規作成したディレクトリにして、試しに

```
$ git diff
```

と打ってみてください。_Not a git repository_ と言うメッセージが返ってくるはずです。
新規作成したディレクトリはgitレポジトリではありません。

### initialize
##### gitの導入

そこで、ディレクトリに対して、次のコマンドを実行してください。

```
$ git init <any PATH>
```

PATHが指定されなければ、カレントディレクトリに対して git　の initialize が実行されます。

メッセージに「Initialized empty Git repository in _/PATH_」と出るはずです。これで晴れてディレクトリをgitレポジトリにできました。

### add / commit　
##### 変更内容の登録

```
$ git add <file>
```

```
$ git commit -m "commit name"
```

gitでのバージョン管理はcommitの単位で行っていきます。

### status / diff
##### 変更内容の確認

コミットができるようになったところで、状況を確認するためのコマンドを実行してみましょう。

```
$ git status
$ git diff <any file name>
```

statusでは前回のcommitからの変更が、

- addが必要な変更なファイル(赤色)
- commitできる状態のファイル(緑色)

で表示されます。

**できるだけ細かな単位でcommitしていく** 癖をつけるといいと思います

### log
##### 変更内容の登録

幾つかのcommitを行ったら、

```
$ git log
```

を実行してください。現在、作業中のブランチのcommit一覧を表示することができるようになります。

_「ブランチって何？」_

という疑問を持たれた方は、もう暫くお待ちください。ブランチ(branch)は次の[バージョンコントロール](#3)の章で扱います。

## 2.ローカルレポジトリと、リモートレポジトリ

今回はリモートレポジトリとしてgithubのレポジトリを想定します。

[ローカルレポジトリと、リモートレポジトリ](#2)の章を始める前に[github](http://github.com)で新しいレポジトリを作成してください。

この章では

- remote
- push
- clone
- pull
- fork

を扱っていきます。

ここで紹介するのはローカルレポジトリに対する操作です。

pushやpullについて紹介するところにも、説明の都合でブランチ(branch)が出てきます。

### remote
##### リモートレポジトリの管理

```
$ git remote -v
```

でローカルレポジトリに登録されているリモートレポジトリの一覧を取得できます。最初の状態ではコマンドを実行しても何も起こらないはずです。

ローカルレポジトリにリモートレポジトリを登録します。

```
$ git remote add <name> <remote repository url>
```

例えば,

```
$ git remote add origin https://github.com/rild/sample_repository
```

と実行するとoriginと言う名前で、[GitHubのユーザー: rild](https://github.com/rild/)のsample_sapositoryと言うレポジトリが新規登録されます。

ここでもう一度、ローカルレポジトリに登録されているレポジトリ一覧を見てみましょう。先ほどと異なり、登録されたリモートレポジトリが出力されるはずです。

### push
##### リモートレポジトリにローカルへのcommitを反映する

登録を確認したら、リモートレポジトリにローカルレポジトリの状態をpushしてみましょう。

```
$ git push <remote repository name> <branch name>
```

上のコマンドを具体的にしてみると次のようになります。
初めての方は試しに

```
$ git push origin master
```

などと実行してみてください。
これはoriginという名前の、ローカルレポジトリに登録された「リモートレポジトリ」
の

「masterというブランチ」

に変更内容(commitのログ)を登録するという意味です。

言い換えれば、「ローカルレポジトリをリモートレポジトリにアップロードする」というイメージでしょうか。

### clone
##### リモートレポジトリをローカルレポジトリにする

自分や他人のリモートレポジトリをローカルレポジトリとする方法が clone になります。

```
$ git clone <url>
```

上のコマンドを実行すると、カレントディレクトリに clone に指定したリモートレポジトリがコピーされます。

url にはリモートレポジトリに指定されている http か ssh のアドレスを使用しましょう。

はじめは http の url を使用するといいと思います。ssh 接続を行うためには ssh key の準備が必要になります。

### pull
##### リモートレポジトリの変更内容をローカルに反映させる
git clone ではリモートレポジトリに対して変更があった場合、

```
$ git pull <remote repository name> <branch name>
```

でリモートレポジトリの変更をローカルレポジトリに反映させることができます。

pull をする際にはアドレスを指定する必要はありません。これは clone してきたレポジトリには最初からリモートレポジトリの情報が登録されているからです。

試しに clone してきたレポジトリで「ローカルレポジトリに登録されている
レポジトリの一覧」の表示を行ってみてください。origin として、オリジナルのレポジトリのアドレスが登録されていることが確認出来るはずです。

_ちなみに_

pullというのは下のテーブルに紹介したfetchとmergeというコマンドを同時に実行している、というイメージです。

|コマンド|内容|
|:------:|:-------:|
|$ git fetch|リモートレポジトリからローカルにデータをダウンロードしてくる	|
|$ git merge|二つのブランチをマージ（合流）させる	|

### push / pull
##### 注意
こちらのサイト

- [Git pullを使うべきでない３つの理由](http://dqn.sakusakutto.jp/2012/11/git_pull.html)
- [引数なしのgit pushは危険なので気をつけましょう](http://dqn.sakusakutto.jp/2012/10/git_push.html)

で指摘されているようにpushやpullに関しては注意が必要です。安易に実行すると不幸になります。**特に引数なしでコマンドを実行することはしないほうがいいです**。

```:非推奨
$ git push
$ git pull
```

ブランチを指定しない場合、自分が意図しない変更が起きてしまうことがあるからです。

うっかり実行してしまって意図しない変更が起きた場合も、修正する方法はあります。

ですが、修正は大変なのではじめは「やらかさない様に、注意してpushやpullを行う」ということを心がけましょう。

このページでは git の pull / push 操作でやらかしてしまった場合の対処方法は紹介しません...


### 他人のリモートレポジトリに変更を加える方法 (fork)
自分と全く関係のないリモートレポジトリに対して push することはできません。**権限** が与えられていないからです。

他人のレポジトリに対して変更を加える操作は例えば次のような流れになります。

1. 他人のリモートレポジトリを自分のリモートレポジトリにforkしてくる。
2. 自分のリモートレポジトリにforkしたレポジトリを、ローカルレポジトリに clone してくる。
3. ローカルレポジトリに対して変更を加えて、自分のリモートレポジトリに push する。
4. 自分のリモートレポジトリからオリジナルのレポジトリに対してプルリクエストを立てる。

プルリクエストに関しては４章の[プルリクエスト(PR)を立ててみる](#4)で扱います。ただし、この章で扱うのは上で紹介した流れとは少し異なります。

以上がリモートレポジトリとローカルレポジトリ関連の代表的な操作になります。


## 3.バージョンコントロール
この章で扱っていくのはブランチです。

gitコマンドでは

- branch
- checkout

などを使用します。

### branch
##### ブランチを切る、確認する

gitではブランチという単位で作業を分けて管理することができます。

まずは次のコマンドを実行してみてください。

```
$ git branch
```

現在、作業中のブランチに色がついて表示されます。はじめは   master と表示されるだけだと思います。

このコマンドでローカルレポジトリのブランチ一覧を表示することができます。

では次に、ローカルレポジトリに新しいブランチを作成してみましょう。

```
$ git branch <branch name>
```

branch の後に新規作成するブランチの名前を指定することで新しいブランチを作成することができます。

新規作成したら、もう一度ローカルレポジトリのブランチ一覧を表示してみましょう。先ほどと違い、作成したブランチも表示されるはずです。

### checkout
##### ブランチを切り替える

それでは次にブランチの切り替えをしてみましょう。

```
$ git checkout <branch name>
```

で指定したブランチに移動することができます。

ブランチの作成と移動を同時にやるコマンドもあります。

```
$ git checkout -b <branch name>
```

checkoutにオプションbをつけて実行してみてください。

ちなみに、以下の

```
$ git checkout .
```

checkoutに「. (ピリオド)」を指定するコマンドを実行すると「addしていないレポジトリへの変更をなかったことにする」ことができます。

### ブランチを切る目的

gitのレポジトリにははじめ master ブランチのみがあります。

ブランチを切るときに、どんな切り方をすればいいのか迷った場合、ブランチは **作業単位** で切っていくといいと思います。

バグの修正をしようとしているのか、新しい機能の実装をしようとしているのか、または単にREADMEを作って(編集して)いるだけなのか...

すべての変更を同じブランチで行ってしまうと、混乱が生じてしまうので **ブランチは作業単位で切る** ということを意識して開発をしましょう。

### stash
##### ブランチを切り替え忘れて編集をしてしまった場合 (commitする前)

開発をしていると「ブランチを切り忘れたまま編集を進めてしまう」という事態に陥ってしまうことがあると思います。

でも大丈夫です。commit 前なら比較的簡単になんとかすることができます。

```
$ git stach

$ git checkout -b <new branch>

$ git stash pop
```

以上のような手順でブランチを切る前に作業をしてしまった変更内容を「一旦保留にして、新しいブランチを切って、そちらに適用する」ことができます。


## 4.プルリクエスト(PR)を立ててみる
gitの導入からブランチを切るところまで行うことができたのでいよいよgithubで集団開発を行う際に必要になる (かもしれない) 操作をしていきましょう。

ここで紹介するのは **pushする権限がある** レポジトリでPRを立てるところまでのフローです。

### ローカルレポジトリでの作業
下準備として、は次のようなことをやってください

1. 適当なgitレポジトリでファイルを新規作成 (または編集) してcommitをする。

	この際に status や log コマンドも合わせて使ってみてください。

2. 新しいブランチを切って、新しいブランチに移動する。

	この時点では同じ状態の２つのブランチが存在することになります。

3. 新しいブランチでファイルに変更を加えてcommitしてください。

	ファイルを編集するか、ファイルを新規作成してください。

4. 3までの作業で作った2つのブランチをそれぞれgithubのリモートレポジトリにpushする。

```
ローカルレポジトリで、オリジナルの ブランチA と

そのブランチをもとに作った ブランチA' を作り、

２つのブランチをリモートレポジトリに登録しました。
```

以上の作業が終わったらgithubの方の作業になります。githubでプルリクエストを立ててみましょう。

### GitHub (リモートレポジトリ) での作業

<img width="878" alt="github-create-pull-request.png" src="https://qiita-image-store.s3.amazonaws.com/0/90254/c4ecc637-74c9-0930-3a09-2a863e0deadc.png">

上で紹介した場所でプルリクエストを立てることができます。

ここで、「(上の例で)ブランチA を元に、 ブランチA' をマージするためのプルリクエストを立てる」ことができます。

### GitHubのレポジトリで共同編集者に登録する

<img width="1117" alt="github-add-collaborators.png" src="https://qiita-image-store.s3.amazonaws.com/0/90254/daa3d5b4-62fe-cec5-d5e5-58416f66b4ac.png">

上の画像で紹介している部分で共同編集者に登録すれば、レポジトリに対してpushできるようになります。

ただし、追加された編集者は**masterにpushする権限**を持っていません。ですので、masterに対してpushすることはできなくなっています。

基本的にmasterに変更を加えたかったら「新しいブランチを切って、そのブランチでPRを立てて、masterにマージする」という流れになると思います。

### リモートレポジトリのTree構造を確認する

<img width="1168" alt="github_check_branch_tree.png" src="https://qiita-image-store.s3.amazonaws.com/0/90254/388396fa-a8eb-c6d3-b9d7-2111527ed4d9.png">

GitHubでは右上の (レポジトリをForkするための) Forkボタンの右にある数字から、レポジトリの変更履歴を確認することができます。

_ちなみに_

ローカルレポジトリでも、現在のブランチ ($ git branchで緑色で表示されるブランチ) の変更履歴が

```
$ git log --graph
```

で確認できます。

## まとめ (共同開発でgithubを使う)
「共同開発でGitHubを使うための入門」は以上になります。

まとめます。共同開発をする、となった場合に次のようにすればそれらしいことができるはずです。

---

#### 1. リモートレポジトリを作成する

githubで新しくレポジトリを作る

#### 2. リモートレポジトリにpushするためのローカルレポジトリを用意する

リモートレポジトリをcloneしてくるか、ローカルのディレクトリをgitレポジトリにした後にgit remote addでリモートレポジトリを登録する

#### 3. ローカルレポジトリで作業を行う

ブランチ(branch)を切って、作業をして、addしてcommitする

この時以下の２点に注意する。

- **ブランチは作業単位できること**

- **大きすぎるcommitはしないようにすること**

作業しているブランチのオリジナルに変更があった場合、pullすればいい

#### 4. リモートレポジトリにローカルレポジトリへのcommitをpushする

リモートレポジトリへのpush権限がない場合は、自分のGitHubアカウントのレポジトリに一旦forkして、forkしたレポジトリに対してpushする

push権限を付加するためには、共同開発を行うためのレポジトリの所有者が _<Developing Project Reposiory>/Settings/Collaborators_ から共同開発者のGitHubアカウントをCollaboratorsに追加する必要がある

masterブランチにはレポジトリの所有者以外はpushできない

#### 5. リモートレポジトリにmergeするためにプルリクエストを立てる

マージの際に、コンフリクトが起きる場合プルリクエストのところからマージすることができません。

開発を進める際に、**同じファイルを編集しないようにする** ことでコンフリクトが起きることを避けることができます。

コンフリクトが起きてしまった場合は、ローカルで

```
$ git merge <target branch> <new branch>
```

というコマンドを実行することで (無理やり) マージできます。当然コンフリクトが起きた部分の調整をする必要があります。

---

コンフリクトが起きた場合の対処は今回はやっていないので、このページで紹介しているフローで開発を行う場合は、**同じファイルを別々の人が編集することがないようにする** 必要があります。

複数人で開発をするのは注意することが多くて大変ですが、一人で開発するのとはまた違った楽しさがあります。

この記事が共同開発を始めようとする人の役に立ってくれれば幸いです。

**お気付きの点があれば、どしどしコメント欄で指摘していただきたいです！**

読んでくださって、ありがとうございました。

### Git関連トラブルシューティング用リンク

私が ~やらかしてしまった時に~ お世話になったサイト様を紹介しておきます。

##### stash

- [間違って別のブランチで実装を始めちゃった時にgit stashで別ブランチに編集中のソースを移動する](http://sessan.hatenablog.com/entry/2014/02/06/100935)

##### やらかしてしまった時のいろいろ

- [Gitでやらかした時に使える19個の奥義](http://qiita.com/muran001/items/dea2bbbaea1260098051)

##### 予防策

- [Gitでやらかさないための事前予防策](http://qiita.com/muran001/items/f13742b51da3a22117ee)

気をつけていても（特に初めのうちは）トラブルが起きると思うので、そういう時は焦らずに

- 知ってる人に聞く

- ググる

などして解決を目指しましょう。