親です。

読んだ本とかについて書いてます

【Git】Gitマジ完全理解したから聞いて

おつです。もう半年くらいGitに苦しめられていたんですが、UdemyのGit講座(もう怖くないGit!チーム開発で必要なGitを完全マスター https://www.udemy.com/share/1002Z8BEAdeF5RRHg=/ )見たらスゲエ理解できました。熱の冷めないうちに何点か「なるほど!」となった点を書きます。対象読者はGit使ってるけど背景は押さえてない人、もしくはマサカリ投げたくてうずうずしている人です。

1. Gitのバージョン管理方法

俺がこの三日くらい勉強して最も「Git、ありがて〜〜」と思ったのはバージョン管理の仕方にある。んで、Gitの方式について書く前に、Gitが存在しない世界での話を書いておくけど、そういう世界では「これが最新.txt」方式でバージョン管理をする。

f:id:MaximoNelson49:20190130134846p:plain
「これが最新.txt」方式。最新のファイルがどれか分かるだろうか? *1

「これが最新.txt」方式にはたくさんの問題がある。まずどれが最新のファイルか分からないし、複数人で作業するときにファイルの上書きが容易に起きる。そういう問題を避けるために、Gitではデータファイルだけを保存するのではなく、データファイルの管理情報をヘッダーとして一緒に保存している。
そのヘッダーを「コミットオブジェクト」と呼ぶ。コミットオブジェクトにはツリー情報(後述)のほか作成者や作成日時、なぜその修正が行われたのかを示すコミットメッセージ、そしてそのバージョンの修正前ファイルを示す親コミット情報が含まれる。
この親コミット情報のおかげでGitはバージョン管理ができている(んだと思ってる俺は)。今のバージョンがどのバージョンから作られたのかさえ分かれば、どれが最新なのか、そしてバージョンが枝分かれしていないかなどが分かる。

2. コミットの中身

git addをしてgit commitすると、Gitが管理する全ファイルのスナップショットを取得し、対象ファイルをステージングし、さらにリポジトリに登録することができる。このとき登録されたものをコミットと呼ぶ(と思ってる)。
このコミットには、

  1. blobObject(データファイルの中身を圧縮したもの)
  2. treeObject(データファイルのツリー情報)
  3. commitObject(データの管理用ヘッダー情報)

の三つが含まれる。それぞれについてもう少し詳しく書くと、blobはデータの圧縮そのものを示し、treeはフォルダ構成と圧縮ファイルへのポインタを記録し、commitは(先ほども書いたが)ツリー情報や対象コミットの親コミット情報などが含まれる。
この三つはそれぞれ関連している。commitがtreeを含み、treeにはblobへのポインタが含まれている。スナップショットとして記録されたファイルの状態は、このようにしてリポジトリに登録される。

ちなみに、( Git - Gitの基本 )とかにここら辺が詳しく書いてあるので読むといいと思う。

3. ブランチはただのポインタ

「1.Gitのバージョン情報」に書いたんだが、Gitは親コミット情報があるおかげで最新のファイルがどれだとか、バージョンが枝分かれしているかどうかが分かる。
んで、枝分かれって言ったらブランチのことを書かなきゃならんのだが、上で書いたように、枝分かれがどのように起きているのか管理すること自体はGitの親コミット情報によって管理できている。

ではブランチが何をやっているのかというと、ブランチってのはただのポインタだ。親コミット情報によってGitが管理している枝一つ一つに名前をつけ、人間が見たときわかりやすいように管理するタグみたいなものだ。だから特別なんかすごいことをしているわけではないらしい。

(愚痴なんだけど、俺はブランチがなんかすごいことをしてるんだと思っていてブランチの説明を聞いたときすごく混乱した。ブランチによって並行開発が可能になっている、って言われるたびにコミットが連なっているというだけでは実現できていない何かすごいことをブランチがしているんだ....と思って恐れおののいていた。けど実際、Gitはコミットデータを追うことによって枝分かれを管理しているし、ブランチの旨味は、その枝分かれしている状況においてそれぞれの枝の最新をポインタとして記録することで枝の切り替えを簡単にしたり、人間が見て一目で枝があるなと分かりやすくできていることだ。)

4. リモート周りがすごい混乱する

ここは半分わかったようなわかってないような感じなんだけど、リモートってのが、gitにはある。そのおかげで、複数人がオンライン上のリポジトリを介して一緒に開発できるようになる。
リモートリポジトリはリポジトリっていうくらいだからコミットデータがたくさん入っていて、コミットデータがたくさん入っているってことはそこで枝分かれがしたりもしているわけだ。
その枝をリモートブランチと呼ぶ。リモートブランチはもちろんローカルでは編集できない。できるのはgit fetchによってローカルにリモート(追跡)ブランチを作成し、それをgit mergeすることによってマージしてローカルブランチに取り込むことだ(もちろんgit pullしても良い)。

今リモート関連で疑問に思っているのは、git pushしたとき、リモートリポジトリではpush時の最新コミットデータが登録されるのか、それとも前回リモートからpullしたときからの差分が登録されるのかってことだ。前者だと親コミット情報の不整合が起きそうだし、後者だと差分を取ったときに別の人の修正分が差分に浮いてきてしまうんじゃないかってなって謎が深い。まあどうにかしてんだろうけど、どっちでやるのを正解にしたんだろうなって疑問に思ってる。

5. 特に分からんところ

ツイート貼り付ける。

とりま以上!!

*1:最新のファイルはもう一階層上にある「はてな原稿_提出用.txt」です。