『Gitをはじめから丁寧に』の勧めとメモ

## はじめに

Gitはあらゆる開発において必要不可欠ですが、独自の概念が多く、初見だと理解が難しいです。
そこで紹介したいのが[Git をはじめからていねいに](https://github.com/takanabe/introduction-to-git)です。
ネット上で無料公開されていますが、市販の書籍より遥かに優良な教材です。
丁寧な説明で根本的な理解を進めながら、体系的にGitについての知識を習得できます。
Gitを用いた実践的な開発に進む前に、あるいはメンターから教えて頂く前に、是非一読をお勧めします。
余談ですが、**私は『Git をはじめからていねいに』を読んでからエラー文への抵抗感がなくなるという効果もありました。**

リンクから直接参照して頂ければと思いますが、各章毎のまとめやコマンドの逆引きを投稿させて頂きます。

## 各章のまとめ


### 1.gitとはなんぞや

>
 - Git を使う場合は(ふつうは)みんながそれぞれ手元に自分用のリポジトリを持つ
 - みんなはそれぞれ自分で行った変更を自分のリポジトリに反映させる
 - 誰かが行った変更を誰かのリポジトリから自分のリポジトリに取り込んだり、逆に自分のリポジトリ
 - 行った変更を誰かのリポジトリに取り込んでもらうことで複数人での作業を行う


### 2.ひとりでつかう - はじめてのコミット

>
- workspaceという作業ディレクトリに対応するリポジトリは、 workspace/.git に作られる
- 作業ディレクトリで作業しただけでは、コミットしたときに Git はその変更内容をリポジトリに登録していいのかどうかわからない
- なので、git add などのコマンド(その他のコマンドも後で出てきます)をつかって、変更したファイルをstageする(「staging area」に置く)
    - 一度 stage されたファイルは、 git rm --cached などのコマンドを使って unstage する(「staging area」から取り下げる)ことができる
    - git commit を行うと、エディタが立ち上がるのでコミットメッセージを書いて保存、終了する。すると、staging areaに上がっていた変更内容がコミットメッセージとともにリポジトリに反映される。このとき、stage されていたファイルの内容とコミットメッセージは「コミットオブジェクト」としてリポジトリ内に保存されている。

### 3.ひとりでつかう - にどめのコミット

>
- コミットには親子関係がある
- コミットオブジェクトには「親コミットはどれか」という情報と、「この瞬間のファイルの状態」という情報が入っている
- これらのふたつの情報を比べることによって、Git さんはいつでも「その 2 つのコミットの間にどのような変更が行われたか」を知ることができる

### 4.ひとりでつかう - どんどんコミット

>
- 「ファイルのリネーム、移動」は、実質は「新しい場所(名前)に同じ内容のファイルを作って、古い場所にあるファイルを消す」という動作である
- なので、ファイルをリネーム/移動 した場合は、「新しくファイルができたよ」という情報を ```git add``` で stage、「古いファイルは消えたよ」という情報を ```git rm``` で stage することでリネーム/削除が表現できる。
- ```git mv``` を使うと、「作業ディレクトリ内のファイルのリネーム/移動」と、「その変更を stage」を一気にやってくれる

### 5.ひとりでつかう - ブランチを知る

>
- Git のブランチは「コミットオブジェクトを指し示すポインター」である
- リポジトリには最初から「master」というブランチが存在している。
- HEAD という特殊なブランチも存在していて、このブランチは「現在選択しているブランチ」を指している。
- ```git branch new_branch_name ```とすることで、新しいブランチを new_branch_name という名前で作成することができる
この新しいブランチは、現在選択しているブランチが指しているのと同じコミットオブジェクトを指している。
- ```git checkout some_branch_name``` とすると、
    - "some_branch_name" という名前のが指しているコミットオブジェクトの状態が作業ディレクトリ内に復元される
    - "some_branch_name" が選択された状態になり、HEAD が some_branch_nameを指すようになる
- 新しくコミットを行うと
    - 新しいコミットオブジェクトが作られる。このコミットオブジェクトは、選択しているブランチが指し示していたコミットオブジェクトを親に持つ。
    - 選択しているブランチは、新しくできたコミットオブジェクトを指し示すようになる


### 6.ひとりでつかう - はじめてのマージ

>
- ```git merge branch_name``` で、今選択されているブランチに branch_name という名前のブランチのコミット内容を取り込むことができる
- マージするときには「マージコミット」という特殊なコミットが行われ、マージコミットのコミットオブジェクトは親をふたつ持つ
- そのマージコミットが持つ「この瞬間のファイルの状態」は、ふたつの親が持っていた内容を合わせたものになる
- ```git branch -d branch_name```とすることで、branch_name という名前のブランチを消すことができる


### 7.ひとりでつかう - もっとマージ
>
- なにか作業を行うときはブランチを切ってから行うと、いつでも「その作業を行う前の状態」に戻れるので便利
- 「分岐」してないブランチをマージするときには Fast-foward という手法が取られる
    - Fast-foward だと、マージコミットは作られず、たんにブランチが進められる
- Fast-foward したくないときには --no-ff というオプションを付ける
- マージしたときに競合が発生した場合には、手動でマージする
    - ファイルを手動で修正
- ```git add ＜修正したファイル＞```として「競合を直したよ」と Git に伝える
- 全部直したら git commit でマージコミットを完成させる


### 8.ひとりでつかう - 過去を改変

>
- 今いるブランチが「履歴上のどこから分岐したのか」という過去を改変するためには、```git rebase```を使う。
- rebase をすると、分岐元から今までに行ったコミットの変更内容を、新しい分岐元からひとつずつイチから適用しなおしてくれる。
- 直前のコミットという過去を改変するためには、```git commit --amend``` を使う

### 9.みんなでつかう - ベアリポジトリとクローン,リモートリポジトリ
>
- 手元のリポジトリでの変更内容を他のリポジトリに反映したり、逆に他のリポジトリでの変更内容を自分のリポジトリに反映するためには、そのリポジトリを「リモートリポジトリ」として登録しておかなくてはいけない
    - git clone でリポジトリを複製した場合、Git が勝手にこの複製もとを「origin」という名前でリモートリポジトリに登録してくれる
    - そうでない場合は、 ```git remote add <名前> <場所>``` でリモートリポジトリを登録できる
- リモートリポジトリに存在するブランチやコミットを手元に複製するためには、 git fetch ＜リモートブランチの名前＞ を使う
    - git clone でリポジトリを複製した場合は、clone の段階ですでに手元のリポジトリに複製されている。
    - リモートリポジトリに存在するブランチは、手元のブランチにコピーしてくるときには「リモートブランチ」という形でコピーされる
- リモートブランチに直接コミットすることはできないので、このリモートブランチを追跡するためのブランチを手元のリポジトリに作成する必要がある。
    - あるリモートブランチを追跡する新しいブランチを作成したい場合は、git branch <新しいブランチ名> <リモートブランチ名>
    - すでに手元に存在するブランチであるリモートブランチを追跡したい場合は ```git branch --set-upstream-to=＜追跡したいリモートブランチ＞ ＜手元のブランチ＞```


### 10.みんなでつかう - push pull

>
- リモートリポジトリに手元の変更を反映したいなら、```git push```
    - 追跡ブランチに対しての変更はそのまま ```git push```
    - 新しいブランチを作りたいなら ```git push ＜リモートリポジトリの名前＞ ＜手元のブランチ＞:＜リモートのブランチの名前＞```
    - ブランチを削除したいなら ```git push ＜リモートリポジトリの名前＞ :＜リモートのブランチの名前＞```
- リモートリポジトリから手元に変更を持ってきたいなら git fetch
    - リモートリポジトリのコミットとブランチを持ってくる
    - リモートリポジトリのブランチはリモートブランチとして作られる
- fetch のついでに merge も一緒にやりたいなら、```git pull```


## 付録 ー 逆引き Git コマンド

#### リポジトリの作成
##### 現在のディレクトリを作業ディレクトリとしてリポジトリをはじめから作成したい

```$ git init```

##### 既存のリポジトリを複製したい

```$ git clone ＜複製元＞ ＜複製先＞```
--bare オプションを付けると、作業ディレクトリは複製されず、リポジトリだけが複製される

- clone してきた場合、複製もとのリポジトリが自動的に origin という名前でリモートリポジトリに登録される
    - 複製もとのブランチはすべて「リモートブランチ」として複製される
    - origin/master 追跡する master というブランチが作成される
    - master の内容が作業ディレクトリにチェックアウトされ、復元される。

#### 作業ディレクトリの内容をコミット

##### 作業ディレクトリの変更内容をstage, unstageしたい

```$ git status```
するとたいてい「こういうときはどうしてね」と書いてあるのでそれに従うと良い。

##### コミットしたい

```$ git commit```

- -m ＜コミットメッセージ＞ を付けて実行するとエディタを立ち上げずにコミットメッセージを入力できる

#### 歴史を改変

##### 直前のコミットをやり直したい

```$ git commit --amend```

##### あるブランチで行われた変更を別のところからやり直したことにしたい

```$ git rebase ＜ここからやったよということにしたいコミット＞```

#### リモートリポジトリ

##### リモートリポジトリの一覧を表示したい

```$ git remote```

##### リモートリポジトリを追加したい

```$ git remote add ＜そのリモートリポジトリにつける名前＞ ＜リモートリポジトリの場所＞```

##### リモートリポジトリのコミット内容とブランチを手元のリポジトリに取り込みたい

```$ git fetch ＜リモートリポジトリの名前＞```

- リモートリポジトリのブランチは「リモートブランチ」として手元に取り込まれる

#### リモートブランチと追跡ブランチ

##### あるリモートブランチを追跡する新しいブランチを作りたい

```$ git branch ＜新しいブランチ＞ ＜リモートブランチ＞```
ついでに新しくできたブランチを checkout したいならば、

```$ git checkout -b ＜新しいブランチ＞ ＜リモートブランチ＞```

##### 手元のブランチの変更をリモートブランチを通じてリモートリポジトリに反映したい

``` $ git push ```

- push.default の値が 'simple' ならば、今選択しているブランチのみ push される
- push.default の値が 'matching' ならば、追跡しているブランチすべてが push される
- 手元のリモートブランチが「リモートリポジトリ」に追いついていないと push できない
- リモートリポジトリに対する書き込み権限をあなたがもっていないと push できない

##### リモートリポジトリの変更を手元に取り込みたい

```$ git fetch```
```$ git checkout ＜取り込みたいブランチ＞```
```$ git merge ＜リモートブランチ＞ （あるいはリベースのほうが都合がよければ git rebase ＜リモートブランチ＞でもよい）```

あるいは

```$ git pull```

とすると、追跡ブランチにリモートブランチの内容を merge するところまで一気にやってくれる


## 勝手に追記: 逆引きCommand Line[Mac]

原著『Git をはじめからていねいに』内で適宜必要なCommand Lineも紹介されているのですが、まとめられてはいなかったので追記しておきます。

##### ディレクトリ作成

（例 sample_workspaceというディレクトリを作成）


```mkdir sample_workspace```

##### 現在どのディレクトリにいるか確認する

``` pwd ```

##### ファイル作成(例　sampleというファイルを作成)

※ファイルを作りたいディレクトリに移動してから実行してください

``` touch sample ```

##### ディレクトリの中身を表示Ver.1

(普通版。隠しファイルは表示されない）

``` ls ```

##### ディレクトリの中身を表示Ver.2

(発展版。隠しファイルも含めて全て表示される）
※後述のgitファイルは隠しファイルなので、```ls```だけだと表示されません

``` ls -a ```