ことれいのもり

Git保存の仕組みをやさしく解説 スナップショットとコミット

はじめに

こんにちは!Gitをなんとなく使っている「ことれい」 です。

私は今までGitを雰囲気で使ってきました。

しかし、今後の実務でGitの正確な知識が必要になる予感がしています。

そこで、「一度ちゃんと仕組みを知ろう」 と思い、Gitについて学び直しました。


今回からの連続記事で、学び直した過程で知ったことをまとめていきます。

私と同じようになんとなくGitを触っている人はもちろん、Gitが何か分からない初心者でも理解できるように図を多めに説明していきます。


この記事では、Gitはデータをどのように保存しているのかを中心にまとめました。

根本的な部分なので、ふわっとした認識の人はぜひ読んでください。

Gitとは?

Gitとは、ソースコードのバージョンを管理するためのツールです。

といっても分かりにくいので、もっとかみ砕いて説明します。


例えば貴方がRPGゲームを開発していたとして、コマンドバトルの機能をほぼ作り終えたとします。

そんなときに、チームメンバーの一人が突然こう言いました。


「やっぱりアクションゲームにしよう!」


あなたは泣く泣くプログラムを書き換えることになりました。

でも作業が進むと、不安になります。

「もしまたコマンドバトルにしようと言ったらどうしよう」 「どこまで元に戻せば良いんだろう」


ここで役立つのがGitです。

Gitを導入していれば、ファイルの変更履歴を保存できます。

そのため、過去の状態に いつでも 戻せますし、「やっぱり前の仕様がいい!」という迷惑なチームメンバーがいても簡単に切り替えられます。

日々ファイルを変更して作業を進める人の強力な味方となるツール、それがGitです。


では変更履歴をどうやって保存しているかを考えてみましょう。

Gitの保存方法

いきなりですが、Gitはデータの変更をどんな形で保存しているかはっきり答えられますか?

次の三択で考えてみてください


  • スナップショット
  • 差分
  • タイムライン





考えましたか?




本当に?




答えは、、、、

「スナップショット」です!


「差分」と思っていた人がいるのではないでしょうか。(過去の私も差分と思っていました)

スナップショットで記録していることで簡単に差分を得られますが、記録しているやり方そのものではありません。


「タイムライン」と思った人は、残念!

そんな用語は存在しません。

ありそうですが私が適当に考えた選択肢です。

スナップショットとは?

「スナップショット」と言われてピンとこない人はいませんか?

スナップショットとは、「その瞬間のデータ全体まるごと」のことです。

Gitではデータを保存するときに、その瞬間のスナップショット、つまりデータまるごと保存しています。

では、具体的にファイルの変更履歴の流れを見ていきましょう。

ファイル管理とコミット

「スナップショットで保存している」という意味を、ファイル変更を例に見ていきましょう。


ファイル変更(バージョン1とバージョン2)


【図①】

まず、あなたは次の3つのファイルを持っています。


バージョン1

  • ファイルA
  • ファイルB
  • ファイルC


この状態をバージョン1として、スナップショットを取ってGitで保存します。


【図②】

次に、ファイルAをA1に、ファイルBをB1に変更しました。

この状態をバージョン2として、スナップショットを取ってGitで保存します。


バージョン2

  • ファイルA1
  • ファイルB1
  • ファイルC


ファイルAとBは変更されたので、A1とB1に置き換え、ファイルCは変更がないので以前のものをそのまま保存します。


このようにGitでは、各バージョンの状態をスナップショットを取って記録しています。

スナップショットを取って記録することを、「コミット」と言います。

コミットが保持している情報

ここまでの説明で、コミットによって各バージョンの状態を保存できることが分かりました。

実は、コミットが持っている情報はこれだけではありません!

それは、「直前のコミットの情報(親コミット)」です。


親コミットを持つファイル変更


先ほどのファイル変更の例をもう一度見てみましょう。

バージョン2からさらにファイル変更を行ない、バージョン3まで作りました。

このとき各コミットは「親コミットは何か?」という情報も持ちます。


【図①】

バージョン1は最初のコミットです。

そのため、直前のコミットはなしです。

親コミットはなし、とも言い換えられます。


【図②】

バージョン2はバージョン1から変更が加えられたコミットです。

直前のコミットが「バージョン1」という情報を持ちます。

つまり、親コミットが「バージョン1」と言い換えられます。


【図③】

バージョン3はバージョン2から変更が加えられたコミットです。

直前のコミット(親コミット)が「バージョン2」という情報を持ちます。


ここで注意すべきことは、親コミットはバージョン2の情報しか持たないので、バージョン1の情報は持っていないということです。

あくまで、「直前のコミットがバージョン2である」という情報しか持ちません。

では、バージョン1へ戻るにはどうしたら良いのでしょうか。

直前のコミットを持つメリット

コミットが直前のコミット(親コミット)を持つことで、素晴らしい恩恵があります。

それは、コミットを辿ることで以前の状態に戻せるということです。


例えばあなたがバージョン3で作業をしていて、バージョン1に戻したいと思いました。

ここで直前のコミット、つまり親コミットの出番です。

コミットの親コミットを辿ってバージョン1のコミットを探すことができます。


もう一度先ほどの図を見てみましょう。


親コミットを持つファイル変更


まず、バージョン3の親コミットはバージョン2です。

そこで、バージョン2の親コミットを見ます。

すると親コミットはバージョン1でした。

ここで、目的のバージョン1が見つかりました!


バージョン3のコミット自体は、バージョン1の情報を持ちません。

しかし直前のコミットの情報を辿ることで、バージョン1の情報を得ることができます。

このように親コミットを通じて数珠つなぎのような仕組みになっています。

おわりに

今回大事なポイントは以下の2つです。

  • Gitはスナップショットで保存している
  • コミットが直前のコミットを保持しているので、コミットを辿ることで以前の状態に戻せる


次回はローカルリポジトリ・リモートリポジトリの概念について説明します。

次回:[Gitリポジトリの仕組みをやさしく解説 ローカルとリモートの違い] (https://kotorei.com/git/local-remote-85)