初心者がおくる, Git 講座

僕が入社して一番最初に勉強することになった Git の使い方をまとめた時の資料です。
ちょっと情報共有することになったのでいい機会だから残しておこうかなと。。。

同じく新人・新米エンジニアの方やそうでない方にも手助けになればいいなぁ。

いやー、昔の自分が書いたものを見返すのって恥ずかしいですね///
昔って言っても1年前なんですが...
これからも精進します！

---

# Git

## 目次
- Git とは
- Git の利点
- Git の使い方
    - ローカルにリポジトリを作成する
    - ブランチを切る
    - コミットする
    - リモートリポジトリに反映させる
    - 便利機能
- まとめ


## Git とは

ファイルの変更履歴を管理するための、「分散型」バージョン管理ツール

### 単語

- バージョン管理
成果物を作成したり変更したりするたびにその履歴を残すこと


- リポジトリ
バージョン管理用に成果物や変更履歴などの状態が保存される場所


- コミット
リポジトリに履歴を記録すること
コミット時にそのコミットに対しての作業内容等のメッセージを残すことができる。


- ブランチ
履歴の流れを分岐して記録していくためのもの
分岐したブランチは他のブランチの影響を受けず、統合する事ができる。


## Git の利点

- 更新履歴の管理ができる
ファイルに対して「いつ」「だれが」「なにを」したかの履歴が簡単に残せる。
最新ファイルの確認や以前の状態に戻す事、バグフィックスなどが簡単にできる。


- ブランチ運用で機能毎に作業を分ける事ができる
複数の課題が存在した時に、目的毎にブランチを作成して同時に作業することで作業効率の向上が見込める。


- ローカルで作業ができる
「集中型」と比べてリポジトリがローカルにコピーされるため、個人単位で作業が管理でき、オフライン状態でも作業ができる。
ローカルPCへのバックアップにもなるため障害にも強い 。
  - 集中型・・・１つのリポジトリを全員で共有
  - 分散型・・・ローカルPC上にリポジトリをコピーする


## Git の使い方

### ローカルにリポジトリを作成する

- `git init` で新たにリポジトリを作成する
- `git clone <url>` で既に存在するリポジトリをクローン（まるまるコピー）

Git ではローカルのリポジトリに対して履歴を残し、
纏まった段階でリモートリポジトリにプッシュする。


### ブランチを作成する

`git branch <name>` で name ブランチを作成

`git checkout -b <name> <branch>` で別のブランチを指定して、
ローカルに新しいブランチを作成できる。
間違えて作成した場合は、`git branch -d <name>` で削除できる。


- 作業するブランチをチェックアウトする（切り替える）
`git checkout <branch>` で指定したブランチに切り替える事ができる。


- 別ブランチをマージする（統合する）
`git merge <branch>` で指定したブランチを現在のブランチに統合する。


- ブランチの始点を変更する
`git rebase <branch>` で指定したブランチの最新コミットに
現在のブランチの始点を追従させることができる。

基本的には master ブランチを作業のメインラインにして、
master の最終コミットから分岐させた別ブランチで編集作業をする！


### コミットする（履歴を残す）

- ワークツリー
ユーザが作業、編集する領域


- インデックス
リポジトリにコミットする準備をする領域
ワークツリーとリポジトリの間に位置し、ワークツリーからリポジトリにコミットする内容を登録する。


- HEAD
現在のブランチの最新コミット


#### ワークツリーの状態を確認する

自分がどのファイルをどの様に変更したかを確認

`git status` でワークツリー内のファイルの状態が確認できる。
`git diff <file>` でそのファイルの差分が確認できる。


#### インデックスにファイルを追加する（ステージング状態にする）

確認したファイルを `git add <file>` でインデックスに登録

間違えてインデックスに登録してしまった時は、
`git reset HEAD <file>` でインデックスから外す事ができる。

必要なくなった変更は、`git checkout <file>` で編集前に戻せる。


#### インデックスに登録された内容をリポジトリにコミットする

`git commit` でインデックスに登録されたファイルをリポジトリにコミット

この時、指定したエディタが開いてコミットメッセージを残す事ができる。
`git commit -m "message"` でもメッセージをつけてコミットができる。


- コミットメッセージを間違えた！

`git commit --amend` でコミットの変更ができる。
コミットするファイルが抜けていた場合も、ステージング状態にしてから再コミットができる。


- コミットするファイルを間違えた！

`git reset HEAD^` でコミット前の状態に戻す事ができる。
コミットの内容がワークツリーに戻る。
`git reset --hard` ：作業内容ごとまるっと消す


- 変更を取り消したい！

`git revert <commit>` で指定したコミットを取り消す事ができる。
取り消した履歴が残る。


- コミットの内容を知りたい！

`git show` でコミット内容が確認できる。
コミットIDを指定することで、そのコミットの内容も確認できる。
コミットは変更内容が分かりやすい様に、こまめに残す事が重要！


#### コミットメッセージの運用

ぼくのかんがえたーなコミットメッセージ。
と、言うより、メッセージの最初にタグ付けしておくことでコミットのジャンル分けができていいなーって。。。
僕が管理する時に使う主なタグはこちら。

- [create]・・・新規作成/新規追加
- [add]・・・追加実装
- [change]・・・仕様変更/リファクタリング等でのコード修正
- [fix]・・・バグフィクス
- [delete]・・・削除


### リモートリポジトリに反映させる

- origin
リモートリポジトリの代名詞	


#### リモートの状態を確認する

`git fetch` でリモートの最新状態を確認


#### リモートの変更を取り入れる

`git merge <branch>`

リモートに変更がある場合は、ローカルに変更を取り入れてからプッシュする。
この時、マージした履歴が残される。

`git pull origin <branch>` で fetch と merge が一度にできる。


- コンフリクトしてしまった！

ファイルの状態が both modiffied となっているファイルは、
自分の編集が誰かの編集とコンフリクト（衝突）してしまっている。
`git diff <file>` でコンフリクトしている箇所を確認し、エディタ等で直す必要があるよ。


#### リモートリポジトリにプッシュする

`git push origin <branch>` でリモートリポジトリにプッシュ

プロジェクトなど多人数のバージョン管理では、
この後にプルリクエストをして管理者に確認してもらったりもする。


- リモートが更新されていた！

プッシュしようとしたらうまく出来なかった。
fetch で確認すると誰かがリモートの内容を更新していたっていう時があります。よね。。。ありました。。。
その時に pull をすると、自分のためだけにローカルリポジトリにマージすると言う、
無駄なマージコミットが残されて履歴が少し見にくくなる。

fetch でリモートの更新を取り込んでから、 `git rebase origin/<branch>` すると
マージコミットを入れることなく、リモートの更新を取り入れる事ができる。

ただし、一度ブランチをプッシュしている場合はコミットに違いができるのでマージするように！
また、コンフリクトするとどのように解消したかを記録するためにも
マージコミットを残した方がいい場合もある。


### 便利機能

- 編集内容をいったん保存したい！

`git stash` でワークツリーの内容を一時保存できる。
保存した内容は `git stash pop` で取り出す。
`git stash show -p <stash>` で保存した内容を確認できる。
ブランチをチェックアウトする時に、編集内容を残したい時などに使える！


- このコミットほしい！

`git cherry-pick <commit>` で指定したコミットを
現在のブランチに取り込む事ができる。


- コミットの順番を変更したい！

`git rebase -i <commit>` で指定したコミットまでの流れがエディタで開く。
その順番を編集して保存するとコミットの順番が入れ替わる。
squash 指定すると複数のコミットをまとめたりもできる。
ただし、下手をすると大きな事故に繋がる恐れがあるほど強力なコマンドなので、運用には最大限の注意を払うこと！！(戒め)


- デグレしてるけど、いつからか分からない！

過去のどこかにバグの原因があるけど分からない場合は、`git bisect` で探す事ができる。
`git bisect start <bad> <good>` でバグが発生しているコミットと、
正しく動作するコミットを指定して探索を開始する。

探索されたコミットが正しく動作する場合は `git bisect good` 、
しない場合は `git bisect bad` で二分探索で確認していく。
元に戻す時は、`git bisect reset` で戻せる。


- 履歴を確認したい！

`git log` でコミット履歴を時系列順に確認できる。

```
 Gitクライアント 【tig】 をインストールすると、ログが非常に見やすくなる。
 `tig` コマンドで現在のブランチのコミット履歴とその内容を確認できる。
 `tig --all` にすると、リモートも含めた全てのブランチのコミットが確認できる。
 tig 上である程度の Git 操作もできます。

 コミットIDや何を変更したか、その時系列もわかるので使えるととても便利！
```


- 修正内容をファイルにしたい！

デバッグ等で使う内容をファイルに置いておきたい時、
`git diff <file> > patch.diff`
でパッチを作成できる。

作成したパッチは
`patch < patch.diff`
で復元できる。

パッチの作成が異なる環境で行われていると、
適用したいファイル名のパスが異なるためうまく当たらない場合がある。
その時は `patch -p[0-9]` で指定した分パスを省略できるので、ファイルを探しに行くことができる。
`--dry-run` を付けてパッチが当たるかを試してみるのがいいかも。


## まとめ


- コミットは作業/機能単位でこまめに行う

- コミットは分かりやすく綺麗にまとめる

- 作業したブランチをマージして master を伸ばしていく

- 一度リモートにプッシュすると後戻りはできない

- 人に誇れる歴史を作ろう！


## 参考

[Gitを使ったバージョン管理【Gitの基本】 | サルでもわかるGit入門 〜バージョン管理を使いこなそう〜 | どこでもプロジェクト管理バックログ](https://www.backlog.jp/git-guide/intro/intro1_1.html)

[SVNを捨ててGitを使うべき5つの理由 - Qiita](https://qiita.com/YusukeHosonuma/items/14c59f3878d640a401a1)

[GITでリモートブランチへpushする前にやっておくべきこと - ITエンジニアとして生きる](http://d.hatena.ne.jp/ogin_s57/20130624/1372069907)