【社内勉強会】Git初心者から卒業するための準備(2017/03/28)

# 0.はじめに

--------------------------
## 対象者
* 普段Gitのcommit, push, pullを使っている人



--------------------------
## 伝えたいこと
* pullはfetchとmergeの組み合わせ
* mergeにはFast ForwardとAuto Mergeの2種類ある
* conflictの発生原因、解決方法


--------------------------
## 参考図書


![image.png](https://qiita-image-store.s3.amazonaws.com/0/37903/644f3921-0b77-3c5d-72ac-0f5d404cde8c.png)

[Gitが、おもしろいほどわかる基本の使い方33](https://www.mdn.co.jp/di/articles/3421/)

--------------------------
## 目次
1. Gitの概要
2. ハンズオンのための環境構築
3. fetchとmerge
4. conflict
5. Gitの便利な機能
6. 付録


--------------------------
# 1. Gitの概要

--------------------------
## Gitとは？
バージョン管理システム(Version Control System, VCS)。
Linuxカーネルのソースコード管理のために開発された。
2005年に開発された。

--------------------------
## バージョン管理システムの種類

* 集中型バージョン管理システム
    - リポジトリはサーバ上にある
    - ネットワークに接続しないと利用できない
    - Subversion, CVSなど

* 分散型バージョン管理システム
    - リポジトリはサーバだけでなくローカル上にもある
    - ネットワークに接続しなくても利用できる(commitなど)
    - Gitなど

時代は集中型から分散型へ！！


--------------------------
# 2. ハンズオンのための環境構築

--------------------------
## TortoiseGitのインストール

* Git for Windows(v2.12)
https://git-for-windows.github.io/

* TortoiseGit(v2.4)
https://tortoisegit.org/

※OSはWindows

--------------------------
## リポジトリの作成
Aさん、Bさんがリモートリポジトリにアクセスするのを、再現できるようにする。

1. ディレクトリを作成
 
```
remote/ ：リモートリポジトリ
local-A/ ： Aさんのローカル
local-B/ ： Bさんのローカル
```

2. リモートリポジトリを作成（ベアリポジトリ）
remoteディレクトリに対して、コンテキストメニュから[Git Create repository here]を選択
[Make it bare]チェックをONにして、リポジトリを作成。

3. local-A, local-Bに対してGit Cloneする。

4. sample.txtという適当なファイルをlocal-Aディレクトリに配置して、commit, pushする。

5. local-Bに対してpullする

--------------------------
# 3. fetchとmerge

--------------------------
## fetchとは？

リモートリポジトリから最新情報を取得する操作。

### Let's Try
0. local-Aとlocal-Bを同じ状態にする
1. local-Aにcommit,pushする
2. local-Bで[Show log]を実施
3. [All branches]にチェックを入れて、ローカルとリモートのmasterブランチを比較。

### 確認項目
* fetchで最新情報が取得できる
* Gitのlogはローカルリポジトリの中身を見ているだけで、リモートにはアクセスしていない。


--------------------------
## 1個目のmerge(Fast Forward：早送り)

### Let's Try
0. local-Aとlocal-Bを同じ状態にする
1. local-Aにcommit,pushする
2. local-Bでfetch, mergeを実施

### 確認項目
* TortoiseGitのメッセージに[Fast-forward]と表示される
* 履歴グラフが枝分かれしていない。local-Aに対してのコミットが追加された（早送り）だけ。
* fetch, mergeの結果が、普段使っているpullの結果と同じ

--------------------------
### merge(Fast Forward)の図

bugfixブランチをmasterブランチにマージ

![capture_stepup1_4_1.png](https://qiita-image-store.s3.amazonaws.com/0/37903/3a2f7b94-30ed-506e-9bcb-d72d318c0352.png)

↓

![capture_stepup1_4_2.png](https://qiita-image-store.s3.amazonaws.com/0/37903/d1d143ae-e465-ce92-ac8a-3b28b1e9cfe8.png)

[サルでもわかるGit入門](http://www.backlog.jp/git-guide/stepup/stepup1_4.html) より引用

--------------------------
## 2個目のmerge(Auto merge)

### Let's Try
0. local-Aとlocal-Bを同じ状態にする
1. local-Aにcommit,pushする(sample.txtの先頭行を修正）
2. local-Bにcommitする(sample.txtの最終行を修正）
3. local-Bでpullする


### 確認項目
* Merge Commitが追加される
* 履歴グラフが枝分かれしている（親が２個ある）

Gitは自動でmergeしてくれる！


--------------------------
### merge(Auto merge)の図

bugfixブランチをmasterブランチにマージ

![capture_stepup1_4_3.png](https://qiita-image-store.s3.amazonaws.com/0/37903/86df4978-a999-b195-cc34-2a850a815ca2.png)

↓

![capture_stepup1_4_4.png](https://qiita-image-store.s3.amazonaws.com/0/37903/19928193-8bb4-9173-b304-082f2f721ffa.png)

[サルでもわかるGit入門](http://www.backlog.jp/git-guide/stepup/stepup1_4.html) より引用

--------------------------
# 4. Conflict


--------------------------
## Conflictはいつ起こる？

同じファイルの同じ行が修正されたとき
⇒Gitがmergeするとき、どちらを採用すればよいか分からないとき

### Let's Try
0. local-Aとlocal-Bを同じ状態にする
1. local-Aにcommit,pushする(sample.txtの先頭行を修正）
2. local-Bにcommitする(sample.txtの先頭行を修正）
3. local-Bでpullする

### 確認項目
* Conflictが発生する。以下のようなメッセージ。
* ファイルの中身に、[<<<<<<< HEAD]が追記されている。上側が元ファイルの内容。下側がpullした内容。

```sample.txt
C#
<<<<<<< HEAD
Scala
=======
Object-C
>>>>>>> aba32016ef3946904f84e2a1390b37d115e3411f
C++
```


--------------------------
## Conflictの解決方法
TortoiseGitMergeを使う。

### Let's Try
0. local-Bでconflictが発生している状態
1. conflictが発生しているファイルのコンテキストメニュから[Edit Conflicts]を選択
2. conflictしている行を選択して、コンテキストメニュの項目から、coflictを解決する。Mergedウィンドウに赤い行がなくなればOK.
3. [Mark as resolved]ボタンを押す。Gitにconflictが解決したことを知らせる。
4. local-Bでcommitする

### 確認項目
* コミットメッセージ欄に「Conflict」と記入される

--------------------------
## Conflictが起きたときにしてはいけないこと

* conflictを解決せずに[Mark as resolved]ボタンを押して、「<<<<<<< HEAD」がある状態でcommitする

* commitするとき、自分が修正していないファイルをcommit対象からはずす（他のユーザが修正したmerge用のファイルかもしれない）

* commitするとき、自分が修正中のファイルをcommitしない（[stash save ]で差分がない状態にしてから、pullすべき）

メンバーにGit初心者がいるならば、conflictの扱いには注意すること。
「conflictが発生したら、何もしないで呼んでください」などの対応が必要。

--------------------------
## Conflictが発生しないようにするには（自分の考え）

Fast ForwardなMergeが行われるようにする。

* 作業開始する前にはpullして、できるだけ最新なソースに対して修正する
* 同じファイルを修正しなくてもよいようなファイル設計にする(機能ごとにファイル分割など）


[Abort Merge]でConflict発生前の状態に戻すこともできる。
（差分がある場合は大丈夫？）

--------------------------
# 5. Gitの便利な機能

--------------------------
## [Try] 差分を見たい

* コミット間の差分
* ブランチ間の差分
* 差分のあるファイルを出力[Export selection to]
* ファイルを選択して[Blame]. コミットのよる変更行がわかる。



--------------------------
## 1ファイルに対しての複数個所の修正を、複数のコミットに分けたい場合
1. コミットの対象のファイルを選択
2. コンテキストメニュから[Restore after commit]を選択
3. 差分エディタで、コミット対象外の修正を削除する
4. commit
5. 上記の操作で取り消した修正が、元に戻る


--------------------------
## コミットを取り消したいとき

### pushする前に取り消したい
git resetを利用する。


### pushした後に取り消したい
git revertを利用する. 打ち消すためのコミットが追加される。
コミット自体は消せない。
過去は変えられない！！



--------------------------
## Rename前のログを見る

ファイルを選択してTortoiseGitの「Show log」したとき、Rename前のログが見られない。
以下、Rename以前のログを見る方法。

1. Git Logウィンドウで、Statusが「Rename」のファイルを選択
2. 右クリックメニュから「Show log before rename/copy」を選択

![git-log.PNG](https://qiita-image-store.s3.amazonaws.com/0/37903/0698ccf5-9ffd-d34c-7670-5f311728eaca.png)


### Git Bashの場合

```bash
git log --follow [filepath]
```

>--follow
Continue listing the history of a file beyond renames (works only for a single file).

引用元: [git-log Documentation](https://git-scm.com/docs/git-log)


--------------------------
## 知っておいて欲しい機能

* git rename ：ファイルの移動
* stash save：差分を一時的に保存（コミットしたくないけどプルしたいとき）
* git tag ：コミットに目印をつけたいとき（リリース完了後など）
* git branch: 同時に複数の作業を行うとき




--------------------------
# 付録

--------------------------
## Gitの開発フロー

* git-flow
* github-flow

現場に合った最適なフローを探しましょう！

--------------------------
## [Try]Gitをコマンドで使ってみよう

Git Bashを利用