なぜ僕らはGitでバージョン管理をするのか

プログラミングを初めて3ヶ月くらいしたとき、**Git**ってものがあると知りました。
**バージョン管理**をしてくれるシステムなんだってさ。
ファイル名に「test_20200615.php」なーんて書かなくて済むらしい。

便利らしいね、これ。

でも別にGit使わなくても個人開発出来てるし？
コード書いたらファイルを上書きしても困ってないし？

**バージョン管理できるのはわかった**よ。それで**どんないいことがあるの？**

…という、過去の自分の疑問がありました。
今ではITエンジニアとなりGitなしでは生きていけなくなった自分自身が全力で答えていきます。

（ バージョン管理システム全体を代表してGitを例にあげてます）
（SubversionでなくGitを使う理由の記事ではないのであしからず）

・2020/06/29追記
この記事の次ステップはこちらに書きましたので、あわせてどうぞ。
[Gitを触り始めてからGithubにpushするまでの流れを誰よりも丁寧に説明する](https://qiita.com/gakisan8273/items/6ebaf9217d140ff1f031)


## バージョン管理のメリット

なぜ僕らはGitを使うのか？
なぜバージョン管理をするのか？
ものすごくざっくりですが、以下2つの大きなところを抑えておけばOKです。

- **以前の状態に戻れる**
- **他人がコードの意図を理解しやすくなる**

例とともに説明していきます。

## 以前の状態に戻れる
あなたはあるシステムを開発して世に出しています。
そして新機能をリリースするためにコードを編集しています。

いよいよ新機能リリースをしました！
しかし動作に**不具合**があり、お客様からクレームの嵐です。
一刻も**早く修正しなければ！！**

修正の方策として、以下の2つが考えられます。

1.  バグを潰して新機能を正常に動かす
2.  新機能リリース前の状態に戻す

1がすぐにできれば理想でしょう。しかし修正に何日もかかってしまえば、お客様に多大な迷惑をかけることになります。
誤ってさらなるバグを生み出してしまう可能性もありますね？
**即座に確実に修正するためには、リリース前の状態に戻す**のがベターです。

さて、**バージョン管理していなかったら**どうでしょう？
「どれがリリース前のファイルだっけ…あ！**上書きしちゃってソースコードが残ってない！！**」
ということになりかねません。

### 「コミット」というセーブ機能を使おう

Gitには**「コミット」**というコマンドがあります。**RPGにおけるセーブデータ**だと思って下さい。
コミットすることでその時点のコードがセーブされます。
**コミットは上書きされるものでなく、いくらでも作ることができます。**

**Gitを使う理由の9割はこのコミットにあります。**
**コミット＝バージョン管理**　と考えても差し支えありません。

RPGではセーブデータを選べば、その時点から再開できますよね？
複数のデータがあれば、複数から選んで再開できますよね？

コミットも同じです。

少しコードを書いて機能を追加したらコミットする。
そうすれば機能ごとのセーブデータが作られて、いつでもそれらの状態に戻ることができます。

つまり不具合が生じてしまっても、**新機能開発直前のコミットに戻れば**、
不具合が発生する前の**ソースコードを即座に反映できます！**
超便利です。

（実際には過去のコミットに戻るのではなく、不具合が発生したコミットを取り消す手法がよく用いられます。）

今は市場不具合を例に出しましたが、開発中でも全く同じことが言えます。
ある程度コードを書いたら、突然正しく動かなくなってしまった経験ありますよね？
動いていた時に戻すために**Undoしたり**、**手作業でコードを書き換えてもとに戻したり**していましたよね？
**コミットしてセーブデータを作っておけば、簡単に巻き戻せます。**

本記事では割愛しますが、このコミットを駆使する事で他にも様々なメリットが出てきます。

## コードの意図を理解してもらおう

バージョン管理のもう一つの大きなメリットはこれです。
**バージョン管理とコードの理解がなぜ繋がるのか**分かりにくいかと思いますので説明します。

引き続き、あなたはあるシステムの新機能を開発しています。
先ほどのバグを直すため、**既存のコードをベースにし、ようやくコードを書き終えました**。

さあリリース前にチームメンバーやリーダーに**コードレビューしてもらいましょう！！**
チェックは大事！
**編集前のコードは正しく動いていました。**
それを維持したまま、新たな機能も正しく動くかを確認することが必要です。

**バージョン管理をしていなかったら**どうでしょう。
編集前のコードとあなたが編集したコードはこうなっています。
さて**どこが変わっているでしょう？**


```react:編集前
handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      history: history.concat([{
        squares: squares,
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }
```


```react:編集後
handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateLoser(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? '-' : 'O';
    this.setState({
      history: history.concat([{
        squares: squares,
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }
```

どこを編集したのか？なぜ編集したのか？**ぱっと見分からんですよね。**
これでは編集箇所の確認漏れが発生し、**バグを見逃す危険があります。**

さて、ここでも**コミット**の出番です。

### コミットは変更した差分を記録する

**バージョン管理している**とこのように**編集前後の差分を表示**できます。


```diff:差分
 - : 編集により消去された行
 + : 編集により追加された行

handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
-   if (calculateWinner(squares) || squares[i]) {
+   if (calculateLoser(squares) || squares[i]) {
      return;
    }
-   squares[i] = this.state.xIsNext ? 'x' : 'O';
+   squares[i] = this.state.xIsNext ? '-' : 'O';
    this.setState({
      history: history.concat([{
        squares: squares,
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }
```

どこが変わったか**一目瞭然**ですね！！
コミットは**変更した差分を記録**します。そして差分を表示することも出来ます。
つまり、どこを変更したかが分かりやすくなります。

これであれば、あなたが**どこを編集したのかが他人に伝わりやすくなります。**

### コミットにメッセージを残そう

どこを編集したか？はこれで分かりやすくなりました。
さて、**なぜ編集したか？も分かりやすくしたい**ですね。

コミットするときには**コミットメッセージ**というメモを紐づけて残すことができます。
これを使えば編集の意図をより伝えられそうです。


`コミットメッセージ： 勝者でなく敗者を計算するようにして、かつデザイナー要望より記号を変更`

```diff:差分
// 省略
    const squares = current.squares.slice();
-   if (calculateWinner(squares) || squares[i]) {
+   if (calculateLoser(squares) || squares[i]) {
      return;
    }
-   squares[i] = this.state.xIsNext ? 'x' : 'O';
+   squares[i] = this.state.xIsNext ? '-' : 'O';
    this.setState({
      history: history.concat([{
// 省略
```

とりあえずこれで、なぜ編集したのかを示すことができました。
しかし**編集箇所が複数あるため、コミットメッセージが一つでは分かりにくい**ですね。
**各編集箇所ごとにコミットメッセージがあるとより分かりやす**いと思いませんか？

### コミットを細かくしよう

先ほどは全て編集し終わってからコミットしました。
**コミットを細かく**していたらどうなるでしょう？

関数の修正をしてコミット、その後記号の修正をしてからコミットしてみます。
**2コミットに分割**しました。



`コミットメッセージ： 勝者でなく敗者を計算するように関数を変更`

```diff:差分1
// 省略
    const squares = current.squares.slice();
-   if (calculateWinner(squares) || squares[i]) {
+   if (calculateLoser(squares) || squares[i]) {
      return;
    }
// 省略
```

`コミットメッセージ： デザイナー要望により記号を変更`

```diff:差分2
// 省略
    }
-   squares[i] = this.state.xIsNext ? 'x' : 'O';
+   squares[i] = this.state.xIsNext ? '-' : 'O';
    this.setState({
// 省略
```


細かくコミットしてコミットメッセージを残すことで、
**どこを、なぜ編集したのかがとても分かりやすく**なりましたね。


### 未来の自分は他人

バージョン管理をすることで他人にコードの意図を理解してもらいやすくなることが理解できたかと思います。
**「でも自分は一人で開発してるからGitは使わなくてもいいかな」**と思ったそこのアナタ！

**自分が書いたコードを1ヶ月後に見て理解できる自信がありますか？** いいや、ない（反語）

先に説明した通り、**バージョン管理なしではコードの意図を伝えることが困難**です。
そして、**伝える相手とは未来の自分自身**も含んでいるのです。

未来の自分が困らないためにも、個人開発でもバージョン管理の導入はおすすめできます。

## まとめると

こんな感じ。

- Gitにおける**バージョン管理とは「コミット」というセーブ機能**を使うこと
- コミットにより、**過去の状態に戻る**ことができる
    - 不具合が生じた時に即座に戻れて便利！！
- コミットにより、**コードの意図を伝えやすく**なる
    - コミットごとにメッセージを残せる
    - 細かくコミットするとより伝えやすくなる
    - **未来の自分にも伝える努力をしよう**

細かくは説明していないので、厳密には違っているところもあります。
が、入り口としてはこの認識で十分すぎるほどです。

また複数人開発についてのメリットもありますが、初学者向けということであえて書きませんでした。
複数人でバージョン管理せずにどう開発するか、僕は知らない。

色々書きましたが、**こんなのを読むよりも自分で使ってみるのが一番理解できます。**
まずは使ってみよう！！

次回は「Gitを使い始めたんだけどいまいちよくわからん」という人のための記事を書きます。

Gitは義務教育に盛り込むべき。

・2020/06/29追記
書きました。こちらも初心者向けになってます。
[Gitを触り始めてからGithubにpushするまでの流れを誰よりも丁寧に説明する](https://qiita.com/gakisan8273/items/6ebaf9217d140ff1f031)