失敗事例から学ぶGitの正しい使い方

#書こうと思ったきっかけ
私がGitを使い始めたときは、様々な誤った使い方をしました。そのせいでよく先輩から指摘を受けました。そして自分が指導する立場になって後輩がGitを使っているのをみていると、やはり同じような失敗をしていました。そこでこれ以上被害者を増やさないためにも、私が失敗した知見をもとに間違った使い方と正しい使い方を書いていきます。

#対象者
Git初心者で、とりあえず使い方はわかったぜ！という人。
使い方が不安な人。

#なぜGit(バージョン管理システム)を使うのか
後輩から「Gitが面倒くさい。なぜ使うの？」と言われたことがあるので、はじめになぜGitを使うのかから書いていきます。私がGitを使うのには大きく3つの理由があると思っています。
##1 Bagの原因を素早く突き止めたい
例えば、規模なプログラムの場合、作っている途中でバグが出たときに、バグを修正しようと思ってソースコードに手を加えたが、そのせいで新たなバグを生んでしまった。しかし、何を変更したことが影響したのか既にわからない状態です。こんなときにGitで管理していれば、正常だったバージョンとのDiffを見ればどこを変更したのかがわかりますし、最悪の場合、良かったときの状態に戻せます。
##2 変更履歴を残したい
例えば自分で書いたレポートを添削してもらい、一部を書き直して「ver2」など新しいファイルを作ったことは無いでしょうか。もしくは、保存してファイルを閉じてしまったあとで、前書いた状態に戻したいと思ったことは無いでしょうか。そんなときにGitで管理していればコミットごとに変更履歴を残すことができ、変更した差分を見たり、特定のコミットの状態に戻したりできます。こうすることで修正毎にいくつもファイルを作らなくても管理ができるのでスッキリします。過去に書いたものをつなげる事もできます。聞いた話によると、卒上論文をGitで管理している先輩もいるそうです。
また、変更履歴を残すことで過去にどんなバグを起こしたかを振り返ることができるので、上達への近道になるかもしれません。

##3 今まで書いたコードを汚さずに新しい機能を追加したい
RPGゲームで難しい選択肢に直面したとき、一旦セーブして別のセーブデータを作り、試してから進めたことはありませんか。それと同じで、現在のコードに新しいコードを追加すると失敗する可能性があるので、一旦別のブランチを作って機能を試し、バグが出なかったらマージする手法をとります。「セーブ=コミット」、「ブランチ=新しいセーブデータ」「マージ=セーブデータの結合」とイメージしてもらうとわかりやすいかと思います。Gitの場合はマージするときにどちらの変更を適用するかを選ぶこともできます。
#本題
ここからは実際に起きた誤った使い方の事例を挙げていきます。
##長期間コミットしない
せっかくリポジトリを作ったのにも関わらず、コミットをしなかったせいで、結局Gitの機能を活かせていない人がいました。Gitはバージョン間の差分を見ることはできますが、コミットしなければそのバージョンが作成されません。新しいモジュールを追加する毎にコミットしましょう。
##コミットしたのに長期間プッシュしない
ローカルでコミットをしたのにリモートリポジトリにプッシュしない人がいました。ローカルのデータが何らかの問題によってなくなったときに作業ができなくなってしまうので、コミットしたら一緒にプッシュもしましょう。クローンすれば前の状態がそのまま戻ってくるので安心できます。
##コメントが適当
私が見たものだと「ちょこっと変更」、「整理」、「OO関数を追加」がありました。書いたプログラムは時間が経てば他人のコードです。これでは具体的に何を変更したのかがわかりません。コメントは、そのバージョンを表すタイトルです。例えば、「タイマーが途中で止まる問題を修正した」「閉じるボタンを追加」といったように、編集に関わる他人が見て何を変えたのかすぐにわかるコメントを心がけましょう。ちなみに「ooの関数を追加した」レベルで細かく書く必要はありません。コードの差分を見れば関数を追加したことはわかりますし、その関数が何なのか他人はわかりません。

##実験したい機能毎にブランチを作る
新しい機能を追加するときはブランチを分ければいいんでしょ？と聞きかじった知識を実践したひとがいました。まるでぶどうの房のように小さい機能毎にブランチを分岐させて実験し、いざコミットするときに大量のコンフリクトが発生して苦労しました。(私ですw)
ブランチは、新機能を追加して依存関係やバグを修正する場であり、**自分が知らないことを実験する場ではありません**。ちょっとためしたいからといってやたらにブランチを増やさないようにしましょう。一度も作ったことの無いものはプロジェクトを作って試すのがよいでしょう。
##変更毎に別ファイルを作る
せっかくGitを使っているのに、コミットしないでバージョンごとにファイルを作り直している人を見かけました。
変更した内容はコミットで保存しましょう。
##リポジトリ内の全てのファイルをコミットしない
Gitはコミットするファイルを選ぶことができます。しかし、編集していないファイルだからといってコミットしないと後々面倒なことになります。Githubにプッシュできる内容は、現在コミットしてあるファイルだけです。そのため、そのままプッシュすると未コミットのファイルがプッシュされません。また、ブランチを作った場合はコミットしていないファイルはどこにも所属していない扱いになるので管理がややこしくなります。未コミットのファイルがコミット済みのファイルに結びついていた場合に面倒です。
イニシャルコミットでプロジェクト内の全てのファイルをコミットし、削除したファイルも含めて全ての変更をコミットすることを勧めます。
##プロジェクトの外のディレクトリにリポジトリを作る
リポジトリの中に更にプロジェクトが入っているような入れ子の構造だと、環境によってはうまく認識がされないことがあるので、プロジェクト自体をリポジトリにしてしまうことをお勧めします。管理も楽になります。
![リポジトリ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/c4dab72b-591b-6c89-da48-6ff4f8163d74.png)

##masterブランチで作業する
基本的には**masterで作業してはいけません。**個人で書いている場合に問題はあまりありませんが、複数人で開発している場合は深刻な問題が出てきます。ある開発者が途中まで作ったプログラムに自分で機能を追加したいとき、masterをそのまま書き換えたら作業中のものが混ざってしまい、他の開発者が使うときに混乱してしまいます。ですので、基本的には自分で作業するブランチはmasterから枝分かれさせてそこで作業します。バグの確認が済んでからマージし、プルリクエストを送りましょう。そうすることで常にmasterは開発の最新版を安定した状態で保つことができ、バグの混入などにより開発が停滞することを防ぐことができます。
Gitの管理手法の一つに[「Git Flow」](https://www.atmarkit.co.jp/ait/articles/1708/01/news015.html)があります。この手法もmasterは最後までいじらず、developブランチで作業し、機能の実装やバグフィックスなどタスクごとにブランチを作成し作業を行います。作業が完了したらdevelopブランチにマージします。
![gitflow.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/8cb52aaa-ed77-78f2-fc70-d186731c37b3.png)

#おまけ
##Q&A
**Q1:****GitとGithubの違いは何？**
**A1:**Gitはバージョン管理ツール、Githubはソースコードの共有や共同編集をするためのサーバシステムです。(GithubではGitの機能の一部を使うことができる)Githubではファイルを直接uploadする事もできますが、それだと厳密なバージョン管理はできないので、ローカルに作ったGitのリポジトリで管理し、プッシュするのが基本です。

**Q2:プルリクエストはどんなときに使うの?**
**A2:**Githubでは誰でも好き勝手に編集していいわけではありません。通常、リポジトリの管理者が編集をします。
Githubにあるコードをクローンしローカルで編集したら、その編集を元のリモートリポジトリに適用してもらいたいときに使います。

**Q3:developで作業中なのにmasterを変更してしまった。**
**A3:**masterをdevelopにコミットするときにdiffを見ながらひとつひとつ手作業で変更を適用していきましょう。そもそも面倒なのでmasterを編集するのはやめましょう。

**Q4:Git Flow以外のブランチはどんなときに作ればいい？**
**A4:**例えばOSのバージョンごとに少しソースコードが異なる場合にブランチで分けることがあります。macOS用、windows10用、Ubuntu18.04、Ubuntu16.04用などです。他にも使用する機器ごとに分岐させることもありますが、そこは経験しながら少しずつ分かっていくと思います。

**Q5:リベースって何？マージとどう違う？**
**A5:**リベースを行うとリベース先のブランチがリベース元のブランチにつけ変わります。プログラムをリリースする際にマージではなくリベースを行うとブランチの枝分かれがスッキリします。
詳しくはhttp://liginc.co.jp/web/tool/79390#m1
を参考にするとわかりやすいです。

**Q6:リセットするときにhardやsoftなどオプションがあるけど何が違うの？**
**A6:**リセットを行うとローカルリポジトリのブランチは選択したコミットの状態に戻ります。そのときに何を消すかがオプションによって変わります。
**Mixed:**作業中の内容を保持したまま、リポジトリの状態を指定したコミットまでリセットします。[インデックス](https://backlog.com/ja/git-tutorial/intro/04/)はリセットされます。
**Soft:**Mixedと同じく作業中の内容を保持したまま指定したコミットまでリセットします。リセットされる前のファイルの内容はインデックスに登録された状態になります。
**Hard:**指定したコミットまでファイルの内容を完全に戻します。リセット前のコミットまでの変更は全てなくなります。最終手段なので私はあまり使いません。
##おすすめのバージョン管理ツールの紹介
**TortoiseGit**...Gitをコマンドラインで始めたが、謎の呪文を打つばかりで全体像がつかめないという人はまずはこれを使うことお勧めします。Windowsしか対応していないですが、フォルダに入った状態で右クリックすれば様々なコマンドをGUIで簡単に操作することができるので理解が深まります。
[**GitKraken**](https://www.gitkraken.com/)...GitをGUIで使うことができるツールです。TortoiseGitと違い、Atomエディタ上で動くのでMacやLinuxでも使うことができます。
[**CadLib.io**](https://cadlab.io/)...プログラミング向けではないですが、回路図を書く人がバージョン管理をしたいときに使います。
[**GrabCAD Workbench**](https://grabcad.com/workbench)...CADモデリング用のバージョン管理ツールです。CADで図面を書く人がバージョン管理をしたいときに役に立ちます。上書きしてしまったけどやっぱり前の状態に戻したいってときに役に立ちます。
#最後に
今回書いたことが誰かの役に立ってくれたら幸いです。何かあればコメントをお願いします。
#参考
https://hm-solution.jp/lifehack/post2475.html
https://qiita.com/KosukeSone/items/514dd24828b485c69a05
https://www.atmarkit.co.jp/ait/articles/1708/01/news015.html
https://www.sejuku.net/blog/72311