git tutorial for coder

# git tutorial for coder

## あらすじ

HTMLコーダーに git の使い方を説明する必要があったので作成しました。

当初はページ単位で完成したものを圧縮して順次転送して頂く予定でしたが
コーダーに git を使う事に意欲があったのと、指導するコストと得られる対価(差分が管理できる)を比較すると見合うと判断してテーチィングする事となりました。

## 会社が得たいものとコーダーが得たいもの

会社は「git で納品して欲しい」でコーダーは「今後に備えて git で納品する手順を覚えたい」という点です。git の機能を全て覚えるのは大変なので極力を覚える事を減らしたいです。

今回は、`コーダーが作業するディレクトリは基本的に他の人がいじらない` というルールを決めて以下のような制約の元作業します

- コーダーがいじる topic branch を coder/tanaka のように固定して、この branch だけで作業してもらう
- コーダーに git push origin coder/tanaka してもらい続ける
- コーダーが vim を少し使えるので cui での操作を覚えてもらう
- master への merge はエンジニアが行う

GUI ではなく CUI で操作を伝える理由ですが、コーダーさんが remote 勤務であり操作方法を文字列だけで伝える事ができるからです。

## 環境

MacOSX でのお話です。windows ユーザーの方々は適宜置き換えてお読み下さい。
ちなみに私の git version は以下の通りです。使用しているエディタは vim です

```
% git version                                                                                          
git version 2.14.1
```

## git の初期設定

`git init` と `git config` で初期設定の仕方を覚えてもらいます。
最初は git editor が vim になっていなかったり、
github や bitbucket のアカウントをこちら側で指定した場合に git global の author name が使用されるのを防ぎます。

### git init

```
% mkdir ~/practice-git && cd $_
```

おもむろに `git status` を実行してみる。すると `.git` というディレクトリがまだ無いですよと言われます。

```
% git status
fatal: Not a git repository (or any of the parent directories): .git
```

`.git` というディレクトリを作りましょう

```
% git init
Initialized empty Git repository in /Users/xxxxx/practice-git/.git/
```

確認します

```
% ls -al
total 0
drwxr-xr-x    3 xxxxx  staff   102  8 25 11:21 .
drwxr-xr-x+ 192 xxxxx  staff  6528  8 25 11:21 ..
drwxr-xr-x    9 xxxxx  staff   306  8 25 11:21 .git
```

もう一度 `git status` を実行します。`On branch master` となっている事を確認します。

```
xxxxx% git status
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)
```

### editor の設定

editor の設定を確認して下さい。今回コーダーさんは vim を使えたので以下のように設定しました。

```
% git config --global -l | grep editor                                                            core.editor=/usr/local/bin/vim
```

このようなコマンドを実行します

```
% git config --global core.editor 'vim -c "set fenc=utf-8"'
```

### git config

git の設定情報を見てみます。これは全体の設定

```
% git config --global -l
user.name=xxxxx
user.email=xxxx@example.com
core.editor=/usr/local/bin/vim
```

次に `practice-git` での状態

```
% git config --local -l
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
core.precomposeunicode=true
```

今回はプロジェクト毎に user.name と user.emal を設定したので以下のようにします。

```
% git config --local user.name "GivenName FamilyName"
% git config --local user.email "yourname@example.com"
```

### git init と git config のまとめ

作成したディレクトリを git で管理できるように `git init` を実行し、そのディレクトリ内部で操作された作業を記録するときの作業者の名前の付け方について説明しました。

もしわからなくなったら `rm -fr ~/practice-git` すれば最初からやり直せます。

## commit するまでの流れを覚える

`git add` してから `git commit` を実行して差分を記録します。記録された差分を確認するためには `git log` を実行します。

## git add

master branch に適当なファイルを追加します

```
% echo 'hello world' > index.html
```

この状態で `git status` を実行します。

```
% git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        index.html

nothing added to commit but untracked files present (use "git add" to track)
```

index.html が Untracked files と言われています。以下のコマンドを実行して index.html をステージングします

```
% git add index.html
```

この状態で `git status` を実行すると index.html が Changes to be committed になっている事が確認できます。`git add` したこの状態をステージングといいます。

```
% git status                                                                               On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   index.html
```

ステージングの概念は git のかなり重要な要素なんですが理解する事よりも操作を覚えることの方が大事なのであんまり深く言及しませんが興味がある方はこちらの記事がよくまとまっているので参照してみて下さい。

http://daretoku-unix.blogspot.jp/2009/08/git.html

### git commit 

`git commit` を実行します。以下のような画面が表示されると思いますので1行目に commit message を入力します。ここでは `最初のコミット` にしています。

```
最初のコミット
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
#
# Initial commit
#
# Changes to be committed:
#>new file:   index.html
#
```

vim での操作なので入力が終わったら `:wq` で保存します。すると次のメッセージが表示されます。

```
".git/COMMIT_EDITMSG" 11L, 253C written                                                          
[master (root-commit) 8fb5794] 最初のコミット
 1 file changed, 1 insertion(+)
 create mode 100644 index.html
```

### git log

`git log -n 1` を実行します。そうすると以下のようなメッセージが表示されますので確認してください。

```
xxxxx% git log -n 1                                                                      [master ~/practice-git]
commit 8fb579499f6a799025ab93008ae3ddd0ad442d25 (HEAD -> master)
Author: xxxxxx <xxxxx@example.com>
Date:   Fri Aug 25 12:18:45 2017 +0900

    最初のコミット
```

### まとめ										  

追加したファイルを記録するために `git add` と `git commit` での操作を学びました。
過去に commit した内容を確認するためには `git log` を実行します。

ここまでの作業でもしわからなくなったら `rm -fr ~/practice-git` すれば最初からやり直せます。

## topic branch を準備する

個人で開発する場合は master branch で作業しても良いと思いますが、複数人で作業する場合は topic branch を切り出して作業するのが通例です。

先ほどは master branch で作業していので、そこから分岐して作業する方法を学びます。

### git branch 

`git branch coder/tanaka` を実行して `git branch` を実行して下さい。

```
% `git branch coder/tanaka`
Switched to a new branch 'coder/tanaka'
```

ブランチ一覧を表示してみる

```
% git branch
  coder/tanaka
* master
```

branch を移動

```
% git checkout coder/tanaka
% git branch
* coder/tanaka
  master
```

元の branch に戻ってみましょう `git checkout master`

```
% git checkout master
Switched to branch 'master'
% git branch
coder/tanaka
* master
```

もう一度 `coder/tanaka` branch へ移動します。

```
% git checkout coder/tanaka
Switched to branch 'coder/tanaka'
% git branch
* coder/tanaka
  master
```

### まとめ

master branch から topic branch を切り出して、branch 間を移動する方法を学びました。

ここまでの作業でもしわからなくなったら `rm -fr ~/practice-git` すれば最初からやり直せます。

## topic branch での作業を master branch へ merge する

本来だと `git push origin coder/tanaka` のようなコマンドを実行して remote repository 上に branch を push して、そこから PR を作成する、という手順を踏むわけですが、ここでは手元で何度も繰り返し練習しやすいように手元で master branch へ merge する手順を紹介します。

### topic branch: coder/tanaka で commit を作成

先ほどの index.html を編集して commit します。下記の例では `git commit` に `-m` オプションを使っています。

```
% echo 'hello world!!' >> index.html
% git status
On branch coder/tanaka
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")
```

ステージング

```
% git add index.html
git add index.html                                                                       
```

コミット

```
% git commit -m 'index.html を編集した'
[coder/tanaka f41a421] index.html を編集した
 1 file changed, 1 insertion(+)
```

commit を確認します。

```
% git log -n 2
commit f41a42148f80473a0229847929cb8caa46572eb7 (HEAD -> coder/tanaka)
Author: xxxxx <xxxxx@gmail.com>
Date:   Fri Aug 25 13:35:06 2017 +0900

    index.html を編集した

commit 8fb579499f6a799025ab93008ae3ddd0ad442d25 (master)
Author: xxxxx <xxxxx@gmail.com>
Date:   Fri Aug 25 12:18:45 2017 +0900

    最初のコミット
```

ここで一度 master branch に移動して `git log -n 2` を実行してみて下さい。確認したら再び `coder/tanaka` branch に戻ってきて下さい。

## git merge

master branch に移動して coder/tanaka の commit を master に merge します

```
git checkout master
git merge --no-ff coder/tanaka
```

commit log を確認します。

```
% git log -n 3                                                                                    [master ~/practice-git]
commit 23b09659abc46fb3ae0d20b8cf7841b39dc3491c (HEAD -> master)
Merge: 8fb5794 f41a421
Author: xxxxx <xxxxx@gmail.com>
Date:   Fri Aug 25 13:42:44 2017 +0900

    Merge branch 'coder/tanaka'

commit f41a42148f80473a0229847929cb8caa46572eb7 (coder/tanaka)
Author: xxxxx <xxxxx@gmail.com>
Date:   Fri Aug 25 13:35:06 2017 +0900

    index.html を編集した

commit 8fb579499f6a799025ab93008ae3ddd0ad442d25
Author: xxxxx <xxxxx@gmail.com>
Date:   Fri Aug 25 12:18:45 2017 +0900

    最初のコミット
```

### まとめ

topic branch から master branch に合流する手順を紹介しました。この手順は実際には使う事がないのですが、topic branch で作業する感覚を掴むために紹介しました。

## maste branch での作業を禁ずる

という事で基本的にマスターブランチでコミットする事はないのですが、人類はその長い歴史で何度も同じ誤ちを犯してしまう生き物である事が証明されています。そういうわけでマスターブランチでのコミットを禁止したいと思います。

### pre-commit スクリプト

https://gist.github.com/oh-sky/2c3b6cdfa8b941f585e1 をそのまま利用させていただく

`touch .git/hooks/pre-commit && chmod +x $_` してファイルを生成し、以下を追記して保存する

```
#!/bin/sh
BRANCH=`git rev-parse --abbrev-ref HEAD`
if test $BRANCH = 'master'; then
    echo 'Commiting to master is forbidden.'
    exit 1
fi
```

## 作業フロー

基本的な操作に慣れたところで本題。コーダーは原則ひとつの topic branch を作業し続け、他の作業者とはバッティングしない。mater branch への追従(git merge origin/master)も行わない予定なので以下の作業を行えば良い

最初

- git clone
- git config --local に user.name と user.email を設定
- git branch origin/tanaka && git checkout $_

その後以下を繰り返す

- git add && git commit
- git push origin/tanaka
- Github/Bitbuckt 上で PR を作成 && merge

## あとがき

伝えるべき基本操作と本フローで必要な作業がうまくまとまってないのですが、今後のフィードバックで解消したい

## 質問など

質問があればここに随時追記

- branch の削除方法は？ => `git branch -d branchName`