#3 未経験→iOSエンジニアの道のり-git周り

 
# はじめに
未経験からiOSエンジニアになるまでに行ったことをつらつらしています。
前回はアーキテクチャパターンとライブラリについて行ったことを書きました。
今回は`git`に関して少し書こうと思っています。


# Index
1. [#1 未経験→iOSエンジニアの道のり-開発に挑戦~リリースまで](https://qiita.com/57shota/items/6c31fa44340d120bec39)
2. [#2 未経験→iOSエンジニアの道のり-ライブラリと設計](https://qiita.com/57shota/items/6cb8ef6bb466901e53c7)
3. #3 未経験→iOSエンジニアの道のり-git周り　←　ここ
    4. git
    5. 最低限覚えるよく使うgit
    6. 知っておくべき練習しておくべきgit
    7. コンフリクトした時のアクション
4. [#4 未経験→iOSエンジニアの道のり- 使用ツールやwebサイト](https://qiita.com/57shota/items/b32b4a462d048e69ed32)
5. [#5 未経験→iOSエンジニアの道のり-現場着任前/後の取り組み](https://qiita.com/57shota/items/52b6238442d83cb2f13d)

# 3-1. git
言わずもがなですが、、、`git`はプロジェクトのバージョン管理をしてくれるスーパーツール。バージョン管理とは、更新情報を区切り区切りで確認した、変更したりできるいわゆるセーブポイント。専用のサーバを立て、ターミナルやGUIツールから操作します。
Githubやbitbucketなどのサーバ機能とGUIをあわせた便利なwebサービスもあり、気軽に利用できます。
プログラミングと言われて想像するものに`git`操作はもう含まれている前提でいいと思います。

コミット情報と呼ばれる一括りの更新情報の粒度、即ちどのくらいの変更情報を一つに持たせるかが重要で、チーム開発ではメンバーが確認しやすいよう適切な粒度でまとめるのが大切だと言われています。

前回までにいた、**ある程度のSwiftが読み書きできる** + **設計パターンや有名なライブラリをある程度把握している** に加え **基本的なgit操作が出来る** の三つをある程度できてようやくチーム開発の敷居を跨げるようになるのではと思います。
どれかが不十分だと、まぁジョインは出来てもかなり初動に時間がかかるので効率的ではないです。是非`git`でバージョン管理をして一人チーム開発をやるなどしておいた方が吉かと思います。


## gitの詳細
 コマンド名、gitの概念、リモートやローカルの違い等の細かい`git`の説明はここではしませんが、参考サイトをいくつか載せておくのでそちらを参考にしてください。


参考
https://github.com/
https://bitbucket.org/product/
https://qiita.com/gold-kou/items/7f6a3b46e2781b0dd4a0
https://techacademy.jp/magazine/6235


# 3-2. 最低限覚えるよく使うgit
`git`にも様々なコマンドがあるし、その都度調べればいいので（というか半端な認識で操作すると後悔するので叩く前に調べます）全部覚えろというわけではないですが、検索する時間も命取りになりかねないのでよく使うものは覚えてしまいましょう。


### git clone
```
git clone git@github.com:abc/foo.git
```
ファイルをリモートからローカルへ持って来たい時のコマンド。ファイルを置きたいディレクトリ上で使用。


### git fetch
```
git fetch origin foo
```
リモートからローカルに、**データをダウンロードしてくるだけ**です。
例えば、リモートの最新版origin/masterをローカルで確認したい場合、`fetch`をして最新情報を取得します。この時点では、最新版はローカルに反映されているわけではなく、masterに変化はありません。

|No|Commands|Details|
|:---|:---|:---|
|1|`git fetch origin master`|最新版の取得|
|2|`git log HEAD..FETCH_HEAD`|fetchしたコミットの確認|
|3|`git diff HEAD..FETCH_HEAD`|ローカルと、fetchの差分確認|
|4|`git merge FETCH_HEAD`|fetchをローカルにマージ|


のように最新版の**取得**、**確認**、**統合**という順序が踏めるので、一発で統合したくない時に使用できます。


### git pull
```
git pull origin foo
```
リモートの最新情報を取得して、指定のブランチへ統合するまでを行います。 `fetch`と`merge`をまとめたものです。特に中身を確認せず一発で統合させたい場合はこちらを使用します。


### git branch
```
git branch
```
現在ローカルにあるブランチ一覧を表示します。現在いるブランチも確認できます。
`git branch foo` :  新しいブランチ`foo`を作成できます。
`git branch -D foo` :  `foo`を削除します。


### git checkout 
```
git checkout foo
```
`foo`というブランチに移動（チェックアウト）します。毎度思うのですが、○○にチェックアウトするって違和感ないですか。○○からチェックアウト、じゃないんですね。
`git checkout -b foo` : ブランチ`foo`を作成してそこへ移動します。
`git checkout foo.bar` : `status`にでてくる`foo.bar`という変更ファイルの変更を取り消します。（addファイル群から特定のファイルを取り除ける）


### git status
```
git status
```
`git`管理下にあるプロジェクトを編集した後に叩くと変更されたファイルが表示されます。`add`
`commit` をする前に変更箇所を確認しましょう。


### git add
```
git add
```
`status`で表示される変更ファイルをインデックスにステージングします。
`commit`するためにコミットリストに追加するようなイメージです。


### git commit
```
git commit -m "some comment"
```
コメントをつけてローカルにコミットします。
これでいわゆる**変更点のセーブ**が完了です。上でも書きましたが、粒度を大切にしましょう。

### git push
```
git push
```
ローカルにされた新規コミットをリモートにプッシュ（反映）します。
この際プロジェクトが`github`に基づいているなら、プルリクエストを送って`push`されたコミットがマージできるかレビュアーにレビューをもらいます。
マージなどの概念は上記のリンクから。

ここまでできれば辛うじてチーム開発に参加できるでしょう。これは自分に課せられたタスクをこなす時は必ず実行するコマンドです。あくまで最低限ですが、、、。

一応大まかな作業順に書いたつもりですが、まとめると

cloneする > これから行う作業branchを作成 > そこに移動して作業開始 >
適切な粒度の作業が終わればstatusで変更ファイルを確認 > OKならインデックスにaddする >
どんな作業をしたかコメントをつけてコミットする >
問題なければリモートにpushする > github上でプルリク作成してレビューもらう >
OKなら作業ブランチをマージ


## 3-3. 知っておくべき練習しておくべきgit


### git log
```
git reflog
```
リポジトリのコミットを新しい順に表示します。色々オプション（引数）も付与できます。

|Commands|Details|
|:---|:---|
|`git log --graph`|ツリーを表示してくれます|
|`git log --oneline`|1行で表示してくれます|
|`-n`|任意のn個のlogを表示します。下のreflogでも使えます|


### git reflog
```
git reflog
```
過去に行ったブランチの履歴を確認できます。コミットや、チェックアウトや、リベースなどあなたの過去が表示されます。

### git commit --amend
```
git commit --amend -m "new comment"
```
コミットのコメントを修正したい時に使用できます。日本語入力でコメントを書いているとたまにEnterの叩きすぎでコミットしてしますこともありますので使うこともあると思います。
ミスってコミットしちゃった後にこれを叩けばOKです。

### git reset
```
git reset
```
インデックスの任意の状態にリセット、任意の状態へ戻るという操作が可能です。あの時に戻りたいを叶えてくれるアイテムが、コミットごと消滅させます。
reflogで過去を参照して指定の場所へ、といった感じでセットで使用することが多いです。
こちらもオプションが豊富です。


|Commands|Details|
|:---|:---|
|`git reset --soft`|コミットを取り消す|
|`git reset --hard`|コミットを全て取り消し強制的に戻す|
|``|任意のn個のlogを表示します。下のreglogでも使えます|


上記を使用して、`git reset --hard HEAD^`のようにすると、一つ前に戻れます。
`^` x n でその分だけ戻れます。


### git revert
```
git revert
```
resetのように取り消し系のコマンドです。ニュアンス的には、特定のコミット打ち消すコミットで消滅させるという感じです。コミットは残るので、コメントで変更の意図を残すなども可能です。
コメントを残す/残さないはオプションで選べます。以下を参照ください。


参照
https://qiita.com/chihiro/items/2fa827d0eac98109e7ee


### git merge
```
git merge bar
```
barブランチをfooブランチに反映、統合させたい場合に使用します。チーム開発の場合はgithub上などでマージ操作をすることが多いと思いますがローカルで何かしらの作業をしたい場合はこちらを使用します。
barをfooに取り込みたい場合は自分がfooにいる状態で`git merge bar`をするとbarがfooに取り込まれます。


その際、互いのブランチの変更点が被っている場合はコンフリクト（変更点の衝突）が発生します。その際は手動で修正するなどの操作が必要になります。
下で少し説明します。


### git rebase
```
git rebase bar
```
別々のブランチで開発していたコミットを繋げ直す、とよく形容されます。あとミスると大変なことになるので、rebaseで死ぬとかも言われたりします。私のrebaseバージンもちょっと死にかけました。ver2.0ブランチをリリースしてそちらで新しいブランチを切って作業していたけど、ver1.0で少し変更があったから開発中のver2.0に統合したい！なんて時に使用します。
いつもどっちがどっちか迷いますが、**結合したい、今いるブランチの尻につけたいブランチ**が上記でいうbarです。
イメージが掴むには以下を参照してみてください。
https://www.sejuku.net/blog/71919
https://qiita.com/KTakata/items/d33185fc0457c08654a5


*　※ merge と rebase の違いはこちらがわかりやすかったです*
*http://www-creators.com/archives/1943*


こちらもコンフリクトを起こす時がありますが、少し`merge`と手順が違うので下で説明します。


### git diff
```
git diff
```
`add`する前に変更箇所とインデックスにある変更箇所の差分を確認したい時など使用します。あとはコンフリクトした際の差分確認など。
オプションは色々あるので以下のようなチートシートなどを参照して頂ければと思います。
参照　チートシート
https://qiita.com/shibukk/items/8c9362a5bd399b9c56be


## 3-4. コンフリクトした時のアクション
上記の`merge` `rebase`などを使用した時に変更箇所が被っているとコンフリクトを起こして統合ができません。その時は手動で修正してからもう一度トライします。
例としてローカルにて

1. masterから切ったAというブランチで作業
2. masterから切ったBというブランチで作業
3. BをAにマージ
4. 編集箇所が被っているのでコンフリクト

という前提。
その際、Aにいる状態で`git merge B`をするとXcodeに差分が表示されます。
これを修正していく流れになります。
以下の画像では、コメントが同じ行にあるのでコンフリクトを起こしています。

![スクリーンショット 2019-08-15 14.35.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274090/c68bb6e7-4f02-24ff-c32d-141927a834cd.png)

これを編集して、例えば以下のような行を変えてあげるなどの状態を目指します。

![スクリーンショット 2019-08-15 16.11.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274090/d4ec22ad-3966-8da4-9f99-82778c4a47c3.png)

この結果を目指すのであれば以下のようなフローで解決できると思います。

|No|Commands|Details|
|:---|:---|:---|
|1|`git status`|コンフリクトを起こしているファイルの確認|
|2|`git add`|修正したファイルをadd|
|3|`git status`|修正されていれば緑になっているはずなので確認|
|4|`git commit`|OKなら変更をコミット|


#### rebaseのコンフリクト解消例
rebaseの場合は少しフローが違います。


|No|Commands|Details|
|:---|:---|:---|
|1|`git status`|コンフリクトを起こしているファイルの確認|
|2|`git add`|修正したファイルをadd|
|3|`git status`|修正されていれば緑になっているはずなので確認|
|4|`git rebase --continue`|OKならrebaseを続行|


addを忘れないことと、`rebase --continue`を忘れないことだ大事だそうです。


# #3まとめ
git操作、Linux操作は100%求められる知識です。私は最低限のところは一人チーム開発や知人とのペアプロで練習しました。ここに記載してあるものだけでもやっておけば、業務で使うことになった場合の検索時間短縮、実行の自信等に繋がりますので是非やってみてください。`Swift`のように年単位でバージョンアップして書き方が変わるなどはまずないので、バンバン使って覚えちゃいましょう。私も頑張ります。


### 段階レベル
*  とりあえず何事もなければチーム開発のタスクを一連のgit操作で行える
* githubで繋がるチームメンバーがどう動いているかイメージがつくようになる。
* そのため、チームメンバーのことを考えてコーディング、コメント、git操作などを行うようになる。


設計、git操作を理解するとチームメンバーの行動をより考えるようになりますので、一人で開発している時の自由感のようなものが無くなります。誰が何をやっているか、今後どう影響があるかなど視野が広げてくれる素材になると思うので、これもたくさん触れることができればいいなと思います。

がっつり技術に関しての部分はここまでで、残りの二つでは


* 勉強や調べ物に役立つ間接的なサービス
* その他、個人的に出来るだけ効率的に成長するために心がけていること


を書きたいと思っています。


次 → 4. [#4 未経験→iOSエンジニアの道のり- 使用ツールやwebサイト](https://qiita.com/57shota/items/b32b4a462d048e69ed32)