Git
GitHub
GitLab

commitとかmergeとかfetchとか

書くに至った経緯

「Git = セーブポイント」
「add→commit→push、反対はpull」
程度の理解でなんとかなってきました。

しかし、
「ローカルとリモートでこじれた複数のブランチをどう収拾するか」
という事態に直面し、gitをより深く理解する必要に迫られました。

その中で
「なるほどそういうことか!!!!!」
とアハ体験ができたのでまとめます。

上で挙げた程度の理解度の方にとって、助けになれば幸いです。

想定する読者:
・add / commit / push / pull くらいは何となく使っている。
・でもGitの仕組みは実はよくわかってない。

Git = セーブポイント?

Gitとゲームのセーブは似ています。
(最近のゲームはよく分からないので断っておくと、
 PS2のようなネットに繋がないゲームを想定して書いています)

テレビゲームをイメージしていただくと、
1日目:
今日初めてゲームをして、ステージ1をクリア。ここでセーブ.

2日目:
今日は調子がよくて、ステージ4までクリア。ここでセーブ。

3日目:
今日はステージ5までクリア。ここでセーブ。

これをGitに置き換えると、
テレビ画面に広がっている光景=PCで実際にいじっているソースコードや、そのファイル
セーブデータ        =Gitの「ブランチ」
ということになります。

注意する点は、

「ブランチ=ソースコードそのもの」ではない

という点です。

つまり、commitやpushはファイルのコピーや保存とは違う、ということですね。
テレビ画面に広がっている光景とセーブデータが同じではないように、
ブランチはあくまで、以前の状態を再現するための履歴です。

ゲームのセーブデータとGitのブランチが違う点は次の2つです。

①セーブポイントが全て記録されていく

上のゲームの例だと、セーブデータが
「ステージ1 → ステージ4 → ステージ5」
と上書きされていきます。
3日目の時点では、ステージ5の状態しかロードできなくなります。

しかしGitは違います。
「ステージ1 → ステージ4 → ステージ5」
と、全てのセーブポイントが記録されていきます。
そして、どのポイントの状態も再現できます。

このセーブポイントが連なったものが「ブランチ(=branch:枝)」です。

②ローカルとリモートの2箇所に保存する

「ローカル」というのは目の前にあるPC内の保管場所のこと、
「リモート」というのはインターネット上にある、別の保管場所のことです。

一人で開発するならローカルのみで十分なのですが、
複数人で開発する場合はローカル(=各々のPC)だけしかないと困ったことが起こります。
誰がどこを変えたのかが非常に分かりづらくなってしまうからです。

それが分からないと、自分の書いたコードが誰かのコードとバッティングしてしまい、
ゼロからやり直し、ということも起こり得ます。

そこで、
「全体としてはここまで進んでますよ」という状態をリモートに置き、
各々がローカルで作業しつつキリの良いところでリモートを更新する、
というやり方で開発します。

リモート(=全体の最新の状態)とローカル(=各々のPC)の差分を把握することで、
バッティングややり直しを防いでいます。

二種類のブランチ: 「〇〇〇」と「origin/〇〇〇」

ローカルにあるセーブデータのことを「ローカルブランチ」
リモートのデータのことを「リモートブランチ」と呼びます。

これだけならシンプルで良いのですが、実はローカルにはもう一つブランチがあります。
「リモート追跡ブランチ」
と呼ばれるものです。
(※以降、ローカルにある「リモート追跡ブランチ」
 ではない方のブランチを「ローカルブランチ」と呼びます。)

リモートブランチをローカルブランチに反映させる際、
このリモート追跡ブランチを経由して反映させます。

リモート追跡ブランチはローカル/リモートブランチを作成すると自動生成され、
「origin/〇〇〇」という名前になります。

たとえばappleという名前のブランチだと、
ローカル    => apple
リモート追跡  => origin/apple
リモート    => apple

となります。

リモートブランチ→リモート追跡ブランチへ変更を反映させるコマンドを
「fetch(フェッチ)」
リモート追跡ブランチ→ローカルブランチへ変更を反映させるコマンドを
「merge(マージ)」
fetchとmergeをまとめて行うコマンドを
「pull(プル)」
と呼びます。

ちなみにmergeすると、PCで今開いている実際のコードにも内容が反映されます。
mergeとは実質「セーブデータのロード」といえそうです。

反対向きで見ると、
ソースコードの修正内容をローカルブランチに反映させるコマンドを
「commit(コミット)」
ローカルブランチをリモート追跡ブランチ、リモートブランチの両方に反映させるコマンドを
「push(プッシュ)」
と呼びます。

リモート追跡ブランチの解説は、この記事が分かりやすいです。↓↓

Git で「追跡ブランチ」って言うのやめましょう
https://qiita.com/uasi/items/69368c17c79e99aaddbf

mergeには、リモート追跡ブランチからローカルブランチへの反映だけでなく、
もう一つの意味があります。

mergeの2つの意味

上ではappleという名前のブランチで説明しました。
同じ構造のブランチ「orange」があるとします。

このローカルブランチ「orange」の内容を、
ローカルブランチ「apple」に反映させることもmergeと呼びます。

つまりmergeには、
「リモート追跡ブランチ → ローカルブランチ」
「ローカルブランチA → ローカルブランチB」

の2種類の意味があります。

まとめ

・ブランチとはTVゲームのセーブデータのようなもの
・ゲームと違う点は、ゲームはセーブのたびにデータが上書きされるのに対して、
 ブランチはすべてのセーブポイントが時系列で保存されていく点。
・もう一つの違いは、ローカルとリモートの2箇所に保存する点。
・ブランチには「ローカルブランチ」「リモート追跡ブランチ」「リモートブランチ」
 の三種類がある。
・mergeには、
 「リモート追跡ブランチA(=origin/A)」から「ローカルブランチA」への反映、
 「ローカルブランチB」から「ローカルブランチA」への反映、
 の2つの意味がある。

その他

時間があればイラストも加える予定です。