🐈

脱初心者:Gitについてもう一度知る

に公開

はじめに

この記事を読んでいる方は、Gitをなんとなくで使っている方でしょう。
そんなあなたはどんなコマンドを使うにも恐る恐る使っていて、やらかすのが怖くてたまらないことでしょう。
もしくはなんとなくGitを使っていて嫌な気持ちになっていませんか。

この記事は、そんなあなたに向けてコマンドについてではなく、Gitの内部構造にフォーカスして図解していきます。

そもそもOneDriveとかでファイル共有するのはダメなの?

ダメです。

ダメなところは3つあります。
それは

  • 他人の作業を上書きしてしまう
  • バージョン管理がしづらい
  • 前のバージョンに戻せない

の3つです。

ではAさんとBさんがOneDriveでゲームを作っているとしましょう。

OneDriveを使った作業の簡単な表現
共有ファイルでの作業
こんな感じで作業を表現してみましょう。

話を簡単にするために、1人につき1日1回だけ作業できるとします。
AさんもBさんも、1日に1つだけ作業を進めることができます

OneDriveを使った複数人開発のイメージ
順番にAさんとBさんが作業していていい感じ
AさんBさんが交互に作業していて、今のところいい感じのように見えます。

他人の作業を上書きしてしまう

しかし!
OneDriveを使った複数人開発で起こる問題のイメージ
AさんとBさんが同じ作業をベースに作業してしまった
あーっ!AさんとBさんが同時に、2をベースに3の作業をしてしまいました

このままOneDriveにアップロードすると...
OneDriveを使った複数人開発で起こる上書き問題のイメージ
Bさんの作業はAさんの作業をベースにしていないからAさんの作業が消えてしまった
Aさんの作業をBさんの作業が上書きしてしまいました!

なぜならAさんとBさんは作業中の内容を共有していないので、BさんがアップロードしたファイルにはAさんの作業内容が入っていないからです!
それをアップロードしてしまうとAさんの作業は丸々上書きされちゃいますよね。

つまり、2人が同時並行で作業を進めることができません!!!
それって...本当に複数人開発なんですか...?

バージョン管理がしづらい

さらに、もしBさんが作業1をベースに作業をしている途中に、Aさんが作業2と3をしたとします。

ここでBさんが作業2と3を適応し忘れて、作業1をベースに作業3をしてしまうと...
OneDriveを使った複数人開発でのバージョン管理の難しさのイメージ
さらに作業1をベースに作業しているとき

OneDriveを使った複数人開発でのバージョン管理の難しさのイメージ
作業3どころか作業2も台無しに
ここから先、作業2と3がなかったことになってしまいます。

つまり、Bさんはどれだけ作業の途中でも、Aさんが作業をしたらそれの変更点を教えてもらって、自分のファイルと比較して、適応して...ってしなきゃいけないわけです。

しかし! 少ないファイル数ならまだしも、プロジェクトの規模が大きくなって、10人20人で開発したり、ファイル数が100や1000にまでなってしまうと... 絶対にまともに作業できないですよね。

前のバージョンに戻せない

さらにさらに、
OneDriveを使った開発では前のバージョンに戻せない図
ファイルを上書きしているので前の状態に戻せない
これでは一度変更してしまうと、前の作業に戻ることができません!
どんなにやらかしても、上書きしてしまうともうそれまでなんです。

ということで、OneDriveのようなファイル共有サービスで開発をするのはやめましょう!!!

これらの話は、こちらのブログを参考にさせていただきました。
https://qiita.com/ohakutsu/items/64a128077a8261782c49

Gitについて

では、いよいよGitについてです。

その前に、GitGithub違いについてはご存じでしょうか。

そもそも、Gitには2つの主な機能があります。それは下記の二つです。

  • ソースコードを変更した履歴を見たり管理する
  • 複数人開発のときにソースコードを管理する

ソースコードを変更した履歴を見たり管理することはGitの機能です。

そして、複数人開発のときにソースコードを管理することは、GitGithub両方によって提供される機能です。

これらの違いについてはリポジトリ(repository) について知ることで理解が深まります。

コミットとは

リポジトリについて知る前に、コミット(commit) について理解する必要があります。

コミット とは、Gitにソースコードなどの変更を保存する動作のことです。

具体的にコミットとは、

  • 変更の内容の説明
  • 変更をした人
  • 日時
  • 変更した作業のID
  • どの変更から派生したのか
  • どのファイルをどう変更したのか

という内容の塊であるコミットオブジェクト(commit object) を作り、Gitに保存することを言います。
コミットの流れのコミットオブジェクトを含めたイメージ
コミットの流れ
つまり、作業をした人コミットをすることで変更を保存します。

Gitでは、これらのコミットオブジェクトたちを繋いで作業の履歴として扱います
コミットオブジェクトを繋げて扱うGitのイメージ
つながれたコミットオブジェクト
すべてのコミットは、すべてその前の履歴から派生しています。
なので、最新のコミットは過去の作業をすべて反映した状態になっています。

そして、Gitではコミットオブジェクトソースコードなどのファイルをこんなかんじで大量に保存しています。
Gitでは大量のコミットオブジェクトとファイルを保存している図
Gitのたくさんのコミットオブジェクトとファイルたち

これらのコミットオブジェクトやファイルなどを保存する場所リポジトリ(repository) というんです!

そして、Gitコミットオブジェクトを大量に保存することで、過去の変更の内容を参照したり、他の変更と比較したりすることを可能にしているんです。

これらの過去の変更の参照差分を見れる機能Git最も重要な機能です。それを実現するのがコミットオブジェクトってわけです。

リポジトリとは

先ほど説明した通り、コミットオブジェクトやファイルなどを保存する場所リポジトリです。
つまり、過去の変更の塊をリポジトリと呼んでいます。

さらにこの中で、PCのようなローカル環境にあるリポジトリローカルリポジトリといいます。

作業をする人は、自分が編集したファイルからコミットオブジェクトを作り、それをローカルリポジトリに追加します。
ここまではGitの機能です

そしてGitでは、このローカルリポジトリインターネット上に存在するリモートリポジトリに共有することができます。
リモートリポジトリとローカルリポジトリの関係性のイメージ
リモートリポジトリとローカルリポジトリの関係

こうすることで、互いのPCにあるコミットオブジェクトとファイルを、リモートリポジトリ経由で共有するわけです。

そして、Githubリモートリポジトリであり、それを管理するサービスなんです!

これらの機能を使うことで、作業の内容と履歴を複数人で共有することができます!
さらに、もし仮に誰かのPCが壊れたり、Githubがサービス終了してしまっても、どれか1つでもリポジトリが残っていればそれを共有することで復旧できます。

ブランチとは

これでコミットオブジェクトリモートリポジトリ経由で経由で共有できるようになりました。

しかし!先ほどのOneDriveの例で起きた、他人の作業を上書きしてしまう問題はまだ解決していません。

そこで、ブランチ(branch) という機能を使うことでこの問題は解決することができるんです。

ブランチとは、作るものごとに作業場所を分けるような機能です。
ブランチを作った際のイメージ
ブランチ増殖
JumpとMoveという名前でブランチを作ると、コミットオブジェクトの左上に吹き出しのようなものができました。

この吹き出しは参照(ref) といいます。
参照は各ブランチの最新のコミットを表しています。

MoveやJumpのブランチコミットをしてみると・・・
作ったブランチでコミットした際のコミットオブジェクトと参照(ref)の動きのイメージ
作業で枝分かれしたブランチ
ブランチが枝分かれしました!

これで、互いの作業をうまく干渉しないように進めることができました!

マージとは

ですが、このままではお互いの作業は別のブランチにあり、どちらも互いの内容を反映していません。

ここで登場するのが、マージコミットです。
マージコミットとは、その名の通りブランチ同士を融合するコミットです。

試しにMoveとJumpのブランチを融合してみましょう。
マージコミットをした際のコミットオブジェクトと参照(ref)の動きのイメージ
結果、MoveとJumpをマージすることで、コミットC1が作られました。

Gitでは、マージコミットをすることでそれぞれの変更点をいい感じに組み合わせた最新のコミットを自動的に作ってくれます。

ブランチの参照の位置も最新のC1になっていて、完全にA1とB1が融合したのがわかります。

C1の参照元も、A1とB1の2つになっています。

コンフリクトとは

では、こんな時はどうしましょう?
コンフリクトが起きた際のコミットオブジェクトとブランチのイメージ
MoveとJumpが同じところに違う変更をしている
MoveとJumpで、同じ重力に対して変更をしています。
このままマージしようとするとどっちを変更として適応すればいいかわかりません!

この状態をコンフリクト(conflict) といいます。

さらに、コンフリクトしているときはマージしないほうがいいのでコンフリクトをなくす必要があります。

本来は面倒なこの作業をGitは簡単にしてくれます!
Gitでは、コミットオブジェクトに変更の差分が保存されていますよね。
なので、コンフリクトしている場所がわかり、簡単になくすことができます!

コンフリクトを解消することで・・・
コンフリクトを解消した後のマージコミットのイメージ
コンフリクトを解消したらマージできた
この通り、無事にブランチをマージすることができました!
コンフリクトを解消する方法はいろいろあるので、具体的な方法は今回は割愛します。

Gitを使った作業の流れ

作業の流れとしては、

まず作業をしてインデックスという場所に入れます。

その後に、インデックスにあるファイルからコミットオブジェクトを作ります。

そして作ったコミットオブジェクトローカルリポジトリに保存して、

リモートリポジトリに共有します。

そこから、ほかの開発する人が自分のローカルリポジトリリモートリポジトリの内容を持ってくると・・・

作業フォルダに適応できます!

まとめ

いかがだったでしょうか。

今回の内容をまとめると、

  • OneDriveなどで複数人開発するのは危険
  • Gitを使うと便利
    • コミットで作業の内容を管理できる
    • リポジトリに保存することで作業を共有できる
    • ブランチで複数人開発がスムーズにできる
    • コンフリクトが起きても簡単に解消できる

です。

そして、皆さんが悪戦苦闘しているGitコマンドは、これらのコミットオブジェクトブランチリポジトリを操作するためのコマンドなんです!

これらの内容はGitオブジェクトGitコマンドなどの単語で調べると詳しい内容が出てくると思います。
今回の記事で気になった方やもっと詳しく知りたい方はぜひ調べてみて下さい!

それではみなさん円満なGitライフを~

参考にさせていただいたサイト

https://git-scm.com/book/ja/v2/
https://qiita.com/piro87084806/items/73d5058b93d152a38f56
https://qiita.com/marchin_1989/items/2ec01553e907f3a9e6bb
https://note.com/ryozuno/n/n0ecd4475ebf8
https://qiita.com/ohakutsu/items/64a128077a8261782c49
https://qiita.com/atchy/items/b3cf5cde7263ec62e9b9
https://www.kaitoy.xyz/2015/12/27/git-repository/

Discussion