Gitの知識がほとんどなかったiOSエンジニアがいままで現場で使ったコマンドまとめ

# Gitの知識がほとんどなかったiOSエンジニアがいままで現場で使ったコマンドまとめ

## はじめに
現在現場は 9 ヶ月目で Git は 8 か月間実務+個人開発で使ってきました。
研修中は，SourceTree 使っていたので，できる気になっていたけどそんなことなかった。研修中に実践的にやっておけばよかったと思った。新入社員の方にも聞いて使えない方は使えないようだったので書いてみました。

はじめの現場で結構教えてもらって使えるようになったのでよく使うの，知っておくといいかも的なの書いていきます。個人で使う分のも含まれてるかもしれません。

場合によって適宜追加修正していきます。
スクショも貼ればいいんだろうけど長くなりそうなので実際に打ってみてください。
☆ は経験上で使ったなーって頻度です。

## init 系 ☆
基本的にこれを打つのは個人開発がほとんどかと。GitHub や GitLab の場合はリポジトリ作った段階ですでにプロジェクトがある場合はこのコマンド打て！ない場合は作れってでるのでそれに従うといい。

* GitHub(例)
![github_test.png](https://qiita-image-store.s3.amazonaws.com/0/88266/6e9a3173-7f3b-05ef-8a6f-7112ac702ecf.png "github_test.png")


* GitLab(例)
![gitlab_tests.png](https://qiita-image-store.s3.amazonaws.com/0/88266/f69090dc-4931-5191-da84-fff972a13205.png "gitlab_tests.png")


## remote ☆
Git管理しているリモートリポジトリとか調べるとき下記コマンド。これ打つと origin の意味がわかるようになった。

```bash:ターミナル
$ git remote -v
```

```bash:出力例
origin	git@github.com:MilanistaDev/tests.git (fetch)
origin	git@github.com:MilanistaDev/tests.git (push)
```

この origin とかが下記のときの push 先。

```bash:例
$ git push origin feature/hoge/hoge 
```

必ず origin でなければならないわけでなく，複数のリモートリポジトリを登録できる。個人だとほぼないだろうけど，バックアップ的な使い方はできる。

> git remote add 名前 リポジトリ(.git or url)

```bash:リモートリポジトリ追加
$ git remote add gitlab git@gitlab.com:Milanista224/tests.git
```

出力例は下記。管理しているリモートリポジトリが増える。

```bash:出力例
$ git remote -v
gitlab	git@gitlab.com:Milanista224/tests.git (fetch)
gitlab	git@gitlab.com:Milanista224/tests.git (push)
origin	git@github.com:MilanistaDev/tests.git (fetch)
origin	git@github.com:MilanistaDev/tests.git (push)
```

push するときなどは origin のところを変えるだけ。

```bash:push
$ git push gitlab feature/hoge/hoge
```

逆に消す場合は，下記。
> git remote rm 名前

```bash:リモートリポジトリ削除
$ git remote rm gitlab
```

```bash:出力例
$ git remote -v
origin	git@github.com:MilanistaDev/tests.git (fetch)
origin	git@github.com:MilanistaDev/tests.git (push)
```

既存アプリだとあんまり使うことはないかも。

## clone ☆☆

リモートリポジトリからローカルにもってこれる。名前通りクローン，複製。git 管理もそのままできる。Project を DL するイメージ。

```bash:出力例
$ git clone git@github.com:MilanistaDev/tests.git
```

ここだけの話，いろいろやっててブランチがおかしくなったときは，新しいディレクトリに clone して作業再開するのもありです。大きいプロジェクトだと時間かかるので他の作業の裏でやる。

## status ☆☆☆☆☆

いまどのブランチにいるんだっけ？
いまどのファイル修正してるんだっけ？
そんなステータスを見たいときに実行する。

```bash:ターミナル
$ git status
```

今いるブランチ，変更ファイル，追加，削除ファイルなどが確認出来る。
最も使うかもしれない。

## log ☆☆☆☆☆

これまでのコミットのログを閲覧できる。status と同じくらい使ってる。

```bash:ターミナル
$ git log
```

GitLab でいうところのネットワークみたいなのも確認できる。

```bash:グラフ
$ git log --graph
```

ブランチの生え方などわかるけどこれは GUI ツールの方が綺麗。
コミットのあとに，ブランチをチェックアウトしたときに正しくブランチが切れているかなど一度確認する。

## add ☆☆☆☆☆

ローカルでファイルを編集しました。
よし，ファイルをステージにあげようってときに実行。
コミットする前にアップロードするファイルを add する。

```bash:一つのファイルをadd
$ git add HogePJ/Controllers/ViewController.swift
```

status で赤くなってる(Modified)ファイルのパスをコピペでいい。

```bash:全ファイルをadd
$ git add .
```
追跡したくないディレクトリ，ファイルがある場合は，**gitignore** ファイルを作っておいておく。


編集した覚えのないファイル(xib とか storyboard)を add してしまうと後で面倒なので必ず **status をみること。**

```bash:add+commit
$ git commit -a -m 'Commit Message'
```

でもいいけど，必ず status で不要なファイルがないか確認。

## commit ☆☆☆☆☆
コミットメッセージはチケット名や PJ 名などを先頭に書き，説明をしっかりかく。

```bash:ダメな例
$ git commit -m '修正'
```

```bash:最低でもこれくらい
$ git commit -m 'Ticket#23 タブの画像が表示されなかった部分のバグ修正'
$ git commit -m 'タブ改修 タブの画像をそれぞれ適用'
```

commit は他はそんなに使わないけど，コミットメッセージが適切でなかった場合，1 個前のコミットメッセージを修正する場合は下記を使う。

```bash:amend
$ git commit --amend
```

打つとエディタ(デフォルトならvi)が開くのでミスを修正する。

すでにリモートリポジトリに push してしまったコミットの修正は，
歴史改ざんにあたるため，強制 push をする必要がある。
ローカル(リポジトリ)で修正して，リモート(リポジトリ)にプッシュ時に強制プッシュする。

コミットのタイミングはキリがいいところで行う。
実装前にどの段階でコミットするか考えておくと良い。
複数のファイルにまたがる場合は機能単位，単一(h, m)だとファイル単位みたいな感じ。メソッド単位とかでもいい。
コミットのルールが現場にある場合は従う。

空コミットをする場合は下記コマンドでできます。
GitLab でマージリクエストを作るときとかに書きます。

```bash:空コミット
$ git commit --allow-empty -m '[WIP]空コミット'
```

## push ☆☆☆☆

ローカルリポジトリのコミットをリモートリポジトリにアップロードするときに使う。git add -> git commit -> git push のイメージ。

```bash:ターミナル
$ git push origin hogeBranch
```

Rebase などでコミット履歴の改ざんした場合は，強制(Force) push を行う。オプションは -f。

```bash:ターミナル
$ git push -f origin hogeBranch
```

基本的に **-u オプション** をつけたほうがいいらしい。
対象のブランチをリモートリポジトリに追跡させる機能。
push のミスとか減らせる？基本的に毎回全部打つスタイルなので
よくメリットがわかってはいない。

```bash:ターミナル
$ git push -u origin hogeBranch
```

リモートブランチを削除する場合は，ローカルで削除後，push する。もしくは，下記のように削除する。

> git push リモートリポジトリ :リモートブランチ名

```bash:ターミナル
$ git push origin :hogebranch 
```

## pull ☆☆☆

リモートリポジトリから変更データをもらってローカルリポジトリに変更を適用する。ユースケースでいうと，いろいろな PJ のブランチが master などにマージされたときに master を最新にするとかそういう感じ(言い回し)で現場では使われる。基本的にブランチを切るときは最新にして切るようにする。
個人で使うときは GitLab の AutoMerge 機能を使ったときのリモートとローカル同期くらいの頻度。

> git pull リモートリポジトリ ブランチ名

```bash:ターミナル
$ git pull origin master
```

## fetch ☆☆☆

fetch は pull の一個手前って感じ。対象ブランチの更新があれば最新データを引っ張ってきてリモートリポジトリは最新に，ローカルリポジトリ側は変更を適用しない。このブランチ変更あるかなーってときに試しにやってみる感じ。変更等が明確にわかっていれば pull でいいが，不明なときはまずは fetch してみるって感じ。その後変更あれば適宜 pull する。

> pull = fetch + merge


リモートリポジトリの hogeBranch の更新

```bash:ターミナル
$ git fetch origin hogeBranch
```

git fetch だけのオプション無しを最近は多く使っている気がする。
一応全部更新したいときは下記を実行する。

```bash:ターミナル
$ git fetch --all
```

## checkout ☆☆☆☆☆

ブランチの移動のときに使う。よく使う。

```bash:ターミナル
$ git checkout master
```

ブランチ作って移動もできる。branch コマンドでブランチを作って checkout でそのブランチに移動っていうのをショートカットできる。

```bash:ターミナル
$ git checkout -b hogeBranch
```

加えた変更をなかったことにする，変更した覚えのないファイルの Modified を元に戻す。私の場合は，xib とか Storyboard がほとんど・・・

```bash:ターミナル
$ git checkout HogePJ/Views/Main.storyboard
```

## branch ☆☆☆

ローカルリポジトリのブランチを確認する。

```bash:ターミナル
$ git branch
```

リモートリポジトリのブランチも確認したい。

```bash:ターミナル
$ git branch -a
```

ブランチを作りたい。そして移動する。

```bash:ターミナル
$ git branch feature/hoge
$ git checkout feature/hoge

// ただこれとイコールなのでこっち推奨
$ git checkout -b feature/hoge
```

リモートリポジトリに作ったブランチを反映させる。

```bash:ターミナル
$ git push origin feature/hoge
```

ただし，コミットがなければ MR(マージリクエスト)は作れないので注意。
空コミットを作ってプッシュする方法もある。WIP とかつけとくといい。

```bash:ターミナル
$ git commit --allow-empty -m '[WIP] Initial Commit'
```

その後最初のコミットをした段階で Rebase などでコミットをまとめる。

```bash:ターミナル
$ git rebase -i HEAD~~
```

　
ローカルリポジトリのブランチを消したい。(merge済)

```bash:ターミナル
$ git branch -d hogeBranch
```

ローカルリポジトリのブランチを消したい。(mergeまだ)

```bash:ターミナル
$ git branch -D hogeBranch
```

リモートのブランチを消したい。
それぞれ上記でローカルブランチを消した上で，

```bash:ターミナル
$ git push origin :hogeBranch
```

または

```bash:ターミナル
$ git branch --delete hogeBranch
```

リモートでいらないならローカルでもいらないだろうから前者が多いです。

## merge ☆☆☆

他のブランチの内容をマージする。現場では，◯◯のブランチを取り込んでってそういうふうに言う。

> git merge 取り込むブランチ名

```bash:ターミナル
$ git merge hogeBranch
```

テストのときとか便利なのがある。マージの一歩手前で止めるもの。
機能 1 のブランチで実装中で他の方が実装している機能 2 を取り込んで軽く動作確認してみてってなときにまだ途中だしマージしたくない・・・スタッシュ(後述)かコミットしてから下記を実行する。

```bash:ターミナル
$ git merge --no-ff --no-commit feature/feature2
```

マージコミットはしない。仮マージ的な感じ。
コミットがないので push ができない。間違ってマージしたものを push することがなくなるのでただの git merge ではなくこちらを推奨。

no fast forward は枝生やしたままマージする感じ。
現場の方針に従うのがいいと思いますが，基本的に --no-ff がいいと思っている。どこでデグレったのかわかりやすいと思うので。

上記のマージを解く(なかったことにする)。

```bash:ターミナル
$ git reset --hard HEAD
```

マージ前の状態に戻るのでそのまま実装を続けます。スタッシュした場合はポップします。

## rebase ☆☆☆

マージと同じで取り込むっていう感じだけど，やり方が異なる。
マージは想像通りのマージで，リベースはあたかもマージ後にブランチ切ったようになるイメージ？

```bash:ターミナル
$ git rebase master
```

コンフリクトが起きると解消して continue する必要がある。

```bash:ターミナル
$ git rebase --continue
```

またコンフリクトがあれば同じく止まるので上記を繰り返す。
終わればそのまま作業中のブランチで実装を続ける。

やばいやっぱリベースはや〜めたってときは

```bash:ターミナル
$ git rebase --abort
```

で何事もなかったのように戻る。

**rebase した場合は履歴改ざんになるので強制プッシュしなければならない。**

コミットのまとめもできる。下記のようなコミットしたあとにミスに気づいて再度コミットした場合，コミット数が増えてしまってしかもかっこ悪い。

```bash:ターミナル
$ git commit -m 'Ticket#21 タブのアイコン画像さしかえ'
// タイプミス修正してから・・・
$ git commit -m 'Ticket#21 タイポ(タイプミス)修正'
```

1 個前のコミットとまとめる。#マークがつく

```bash:ターミナル
$ git rebase -i HEAD~~ 
```

こういう系は，fixup，squash とかもある。
また機会があれば書く。

まとめたら **git log** で確認してコミットが修正されていることを確認してプッシュする。すでにリモートリポジトリに push している場合は強制プッシュになる。


## Merge か Rebase か

マージはブランチ同士の比較は 1 回，リベースはリベースするのブランチの変更分のコミットの数の分だけ比較する。取り込むブランチのコミット数少ない場合はリベース，多い場合はマージかなぁって，いままでの現場で使ってみてそう思った。あとはコンフリクトが多そうならマージで 1 回で修正するのがいいかなと。リベースだとコミットごとにみるので丁寧にコンフリクト解消したい場合はいいと思う。コンフリクトないならたったったと進んで気持ちがいい。少なくとも取り込む内容は把握した上でどちらかを選ぶようにする。

よくあるであろう事例で見てみる。


>ある機能 2 を実装中に別の方が実装した機能 1 が master ブランチにマージされました。最新の master を取り込んでくださいって言われて，git fetch して，git pull origin master して・・・，ここまでは同じ。 マージするか，リベースするか。

![001.png](https://qiita-image-store.s3.amazonaws.com/0/88266/47172f1a-d656-80db-badd-82abcdbb376d.png "001.png")


### Merge

```bash:ターミナル(merge)
$ git fetch --all
$ git checkout master
$ git pull origin master
$ git checkout feature/feature2
$ git merge master
// コンフリクトがあれば対応(一度にたくさん出ることも)
// マージコミットができるので push
$ git push origin feature/feature2
```

![002.png](https://qiita-image-store.s3.amazonaws.com/0/88266/5d7fcfd4-314f-88c5-159f-93706996f91a.png "002.png")



### Rebase

```bash:ターミナル(rebase)
$ git fetch --all
$ git checkout master
$ git pull origin master
$ git checkout feature/feature2
$ git rebase master
// master の新規コミットたちと feature2 の内容を比較
// その比較ごとにコンフリクトがあれば対応して --continue
$ git push -f origin feature/feature2
```

![003.png](https://qiita-image-store.s3.amazonaws.com/0/88266/215a44f8-dd53-5536-71e1-55f95acb7f6d.png "003.png")


個人的にはマージコミットがたくさん途中にあるとダサいかなーとか履歴綺麗にしたいとか思うので， Rebase 派だけど現場の方針に合わせてください。

* 比較コミット数が少ない -> どっちでも(Rebase かな)
* コンフリクトが多い -> 丁寧に解消 -> Rebase
* コンフリクトが多い -> コミット数が多い -> Merge
* master に取り込まれたブランチの規模が大きい -> Merge
* master に取り込まれたブランチ数が多い -> Merge

一人でやってるとブランチ切ってマージしてって綺麗な図になるんだけど，チームでやると・・・ね。rebase 使うと多少は綺麗になるっちゃなるんだけど・・・

マージリクエストを出す際は比較ブランチの最新を取得して取り込んだ上で出しましょう。コンフリクトも解消しておくこと。GitLab だと Web  上から Auto Merge できないです。

## stash ☆☆☆

スタッシュは退避。例えば作業中のブランチでまだコミットまでは行けそうにないときに違うブランチでの動作確認(クロスチェックなど)を頼まれました。いままでの作業無駄になるのかよ・・・いやそんなことはないですと。

```bash:ターミナル
$ git stash
```

とりあえず，最後にコミットした状態に戻ってしまいます・・・
動作確認終えました。下記コマンドを打って作業中だったブランチに戻ります。

```bash:ターミナル
$ git stash pop
```

作業中だった状態に戻りました。

スタッシュの履歴もあって

```bash:ターミナル
$ git stash list
```

で戻したいやつ(番号)を把握して，

```bash:ターミナル
$ git stash pop stash@{2}
```

で戻ります。

あとは，仮実装しててもういいやってとき，checkout とかで元に戻すのも面倒だから・・・とか，かなり実装したあとに新しいブランチ切るの忘れてたぁぁ・・・，また一からやり直しかよぉぉ・・・とかそういうときに使えます。

## reflog ☆

**git log** はコミットの履歴， **git reflog** はオペレーション(コマンドとか)の履歴。やらかしてしまったときにみることになるかも。確認だったら 2，3回は使ってる。

## reset ☆

同じくやらかしたときに使うことになる。できればあまり使う機会が少ないのが望ましい。リセットなのでなかったことにする系で使う。

いまのところ仮マージ解くくらいしか使ったことはない。

```bash:ターミナル
$ git reset --hard HEAD
```

使う機会があったらまとめます。

## diff ☆

difference。コードとかの差分にあたる。でもコマンドラインでうつことは少ないのかもしれない。GitHub とか GitLab とかのツールでみることが多いので。

## 大事なこと
* ファイルに不用意に変更を加えない
  - コンフリクトの原因になる
  - タイポをみつけたときなども含む
  - XIB，Storyboard は注意(git checkout ファイル名で対処)

* 少しでもつまったら，迷ったら分かる人に聞く
  - まずは調べる->それでもわからなかったら突き進むのをやめる
  - Git に詳しい上司とか同僚にまず相談する
  - その上で勉強していけばいい(最初からできる人はいない)
  - それから次は自分が教える立場になれるようにする

* ショートカット系で時短を
  - 一文字ずつ打ってもいいけど補完機能使える設定を
  - タイプミスも減ると思われる
  - 記事書きました(Mac + bash)
  - 【Mac, bash】git のコマンド補完
  - http://milanista224.blogspot.jp/2015/09/git-complement.html


## おわりに
Git ができるようになってきたら開発も楽しくなってくる。まだまだマスターには程遠いです。SourceTree みたいな GUI ツールに頼るのもいいけど，エンジニアならターミナル叩いていろいろやってみましょう。前の現場でコマンドラインで分かった上で SourceTree 使ってくださいって言われたのがかなり頭に残ってます。全くその通りだなと。

**わからなくなったら変な操作する前に分かる人に聞く**
これが一番いいです。教えてもらって次からは対処できればいい。
実践あるのみです。

長文になりましたが，ご覧いただきありがとうございました！！