社内Git勉強会

# 本勉強会の目的
:ghost: Gitよくわからん…　
↓
:alien: Gitスコシワカル

Gitのドキュメントを読む足がかりになれればという位置づけ

------------
# 今日の内容

* 状態
* ブランチ
* HEAD
* origin
* git コマンドとの付き合い方
* おまけTips(git stash)

-----------
# Gitの誕生
## 誕生のきっかけ

Linuxカーネルの開発において新しいVCSが必要になった。 :penguin: 

----------
# 3つのエリアとそれぞれの状態を知ろう

* 作業ディレクトリ(Working Directory)
* ステージングエリア
* `.git`ディレクトリ（Repository)

-----------
# 作業ディレクトリ

* 私達が実際にファイルを追加・修正したりするときのエリア。ファイルはuntracked/trackedのどちらかの状態。
* trackedの場合modified/unmodifiedの状態を取る。
* 別名ワーキングツリーとも

--------------
# ステージングエリア

* `git add`するとここに配置される。
* `git commit`時にはこのステージングエリアにあるファイルが対象になる。
* 別名インデックスとも。
* このエリアに追加されるとステージ済みの状態（staged/unstaged)

-----------
# `.git`ディレクトリ（Repository)

* プロジェクトのためのメタデータなどが格納されている。
* `git commit`をするとその情報がここに蓄積される。
* このエリアに追加されるとコミット済み

----------

![https://git-scm.com/book/en/v2/images/lifecycle.png](https://git-scm.com/book/en/v2/images/lifecycle.png)

-------
# ブランチ

**ブランチの前に… git におけるcommitとは？**

> Gitはデータをミニ・ファイルシステムのスナップショットの集合のように考えます。 Gitで全てのコミット（訳注：commitとは変更を記録・保存するGitの操作。詳細は後の章を参照）をするとき、もしくはプロジェクトの状態を保存するとき、Gitは基本的に、その時の全てのファイルの状態のスナップショットを撮り（訳者注：意訳）、そのスナップショットへの参照を格納するのです。 効率化のため、ファイルに変更が無い場合は、Gitはファイルを再格納せず、既に格納してある、以前の同一のファイルへのリンクを格納します。 Gitは、むしろデータを*一連のスナップショット*のように考えます。

**ブランチとは？**
ブランチはある時点のコミットを示すポインタ。

------------
![https://git-scm.com/book/en/v2/images/branch-and-history.png](https://git-scm.com/book/en/v2/images/branch-and-history.png)

------------
## ブランチの種類

* リモートブランチ
* ローカルブランチ
  * リモート追跡ブランチ
  * ローカル追跡ブランチ
  * （通常の）ローカルブランチ

----------
# リモートブランチ

----------
リモートリポジトリにあるブランチ

* **リモート** にあるので普段これを触ったりはしない。
* 私達は`push`/`fetch`を通じてしか操作できない。

--------
# ローカルブランチ

--------
# （通常の）ローカルブランチ

```shell
$ git checkout foo master
```

* 他のローカルブランチ区別するために「通常の」と付けている
* このあと紹介する2つのローカルブランチの特性が無いブランチ

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

* **ローカル** に作成される。
* 最初のcloneかfetchの度、リモートブランチの状態を保存してる。
* リモートブランチの状態を知るには、ローカルにあるリモート追跡ブランチを参照することになる。（リモートブランチとのつながりを持っている）
* `remotes/<remote>/<branch>`という名前で作られる。（省略形は `<remote>/<branch>`)
* このブランチへのコミットは不可

------------
# ローカル追跡ブランチ

* ローカルに作成される。
* リモートブランチへのコミットを発行するためのブランチ。
* 通常のローカルブランチとほぼ同じだが唯一の違いは、リモート追跡ブランチとつながっている事。
* このブランチへのコミットは可能

ローカル追跡ブランチの作成方法をみてもリモート追跡ブランチとつながりを持っていることが見て取れる。

```shell
$ git checkout -b <local_branch>  <remote>/<branch>
```

* 既に手元にあるローカルブランチを、リモートブランチの取り込み先に設定したい場合`git branch -u <remote>/<branch>` 

--------
# `HEAD`　？

* HEADは作業しているブランチを指すポインタ
* `git checkout　<branch>`で HEADが指すブランチが変わる。

-------
```shell
$ git checkout master
```

![https://git-scm.com/book/en/v2/images/head-to-master.png](https://git-scm.com/book/en/v2/images/head-to-master.png)

------
```shell
$ git checkout testing
```

![https://git-scm.com/book/en/v2/images/head-to-testing.png](https://git-scm.com/book/en/v2/images/head-to-testing.png)

-----
```shell
$ git commit # 87ab2
$ git checkout master
```

![https://git-scm.com/book/en/v2/images/checkout-master.png](https://git-scm.com/book/en/v2/images/checkout-master.png)

------
* 現在のブランチの最新コミットを指す。
* 現在操作しているリビジョンのSHA-1ハッシュ(commit id)が必要な場面でHEADを使える。
* パラメータを指定しない場合のデフォルト値になる
* 相対的な指定もできる。
* `HEAD`のエリアスとして`@`が使える

```shell
$ git show HEAD    # 現在の最新コミット
$ git show HEAD^   # 現在の最新コミットの1つ前
$ git show HEAD~   # 現在の最新コミットの1つ前
$ git show HEAD^1  # 現在の最新コミットの1つ前
$ git show HEAD~1  # 現在の最新コミットの1つ前

$ git show HEAD^^^ # 現在の最新コミットの3つ前
$ git show HEAD~~~ # 現在の最新コミットの3つ前
$ git show HEAD~3  # 現在の最新コミットの3つ前
```

上記の通り`^`（キャレット）または`~`（チルダ）で相対指定が可能。

ただし、`^数字`（例えば`HEAD^2`）と入力した場合は注意が必要となる。HEADがマージコミットで親が２つ持つ場合等は`HEAD^数値`は親コミットの指定に使われる。
`~`はマージコミットでは常に最初の親を参照する。

```shell
$ git show HEAD^2~2 # 2番目の親の2つ前
```

-------------
# originとは？

* リモートリポジトリから`git clone`した時にgitがデフォルトでつける名前。読み込み用と書き込み用がある。
* 名前を変更することもできる。
* `git remote -v`で確認できる。
* 複数のリモートリポジトリを登録することもできる。
* 何も特別意味のあるものではない、リモート先の情報を参照するための変数名のようなイメージ

```shell
$ git push 　origin     master
#          　<リモート先>  <ブランチ名>
```

---------
# git コマンドとの付き合い方

コマンド＋オプションを覚えるのも打鍵するのも大変なので、エリアスを活用しよう。

```shell
$ vim ~/.gitconfig
```

例えば

`git add`の取り消し、`git reset HEAD`は覚えにくいと感じたら

```
git unstage <filename>
```

`git commit -m`が長いと感じたら

```
git save <message>
```

`git branch`で常にたくさんの情報(`-a`, `-vv`)を観たいとおもったら

```
git branches
```

もしくはGitクライアントを利用する。(sourcetree, totoise, tig...)

---------

# Tips

--------
# Stash 作業をポケットに一時退避

**使えるケース：**
ある作業中により優先度の高い作業を振られたが、いまの作業はコミットできないし、破棄もしたくないような場合。

`git stash` で今の作業を一時退避できる。

* ステージングエリアと作業ディレクトリの現在の状態を保存し
* 作業ディレクトリをリセットする

```shell
$ git stash save <任意の名前(省略可)>
# 注意点として　untrackedなファイルは対象とならないので先に`git add -A`をしておくのがおすすめ。
```

この時点で最後のコミットした時点に戻ります。
下記で一時保存した内容を確認できます。

```shell
$ git stash list
```

ここでブランチを切って優先度の高い対応を行う。
コミット後元いたブランチに戻って次のコマンドでsaveした内容を復活。且つリストからも削除

```shell
$ git stash pop
```
------
参考

* https://git-scm.com/book/ja/v2
* Gitで困っとときに読む本