LoginSignup
0
1

最初のgitの動作を図で理解する3

Last updated at Posted at 2024-01-07

はじめに

前々回では最初のgitコマンドの基礎的な動作を図で確認し、前回はディレクトリや複数のファイルを含んだコミット動作とコミット内容を復元する処理を確認した。
今回は最初のgitコマンドで複数のコミットの管理方法について確認する。

最初のgitコマンドを用意する

最初のgitコマンドをビルドし、`$HOME/bin-git にコピーして、PATHを通す。

$HOME/bin-git
$ ls $HOME/bin-git
$ cat-file  commit-tree  init-db  read-tree  show-diff  update-cache  write-tree
$ export PATH=$PATH:$HOME/bin-git
$ which cat-file
/$HOME/bin-git/cat-file

1stコミット

この章の内容は前回行った作業と同等である。すでに作業を行っている場合には2ndコミットへ進む。

ファイルの作成

確認に利用するファイルを作成する
$ echo "Hello, World" > README.md
mkdir src
$ echo 'echo "Hello"' > src/hello.sh
$ echo 'echo "World"' > src/world.sh
$ cat README.md ; cat src/hello.sh ; cat src/world.sh
Hello, World
echo "Hello"
echo "World"

コミット

作成したファイルを登録して最初のコミットを行う。

1stコミットを行う
$ update-cache README.md src/hello.sh src/world.sh
$ write-tree
937b5d80b2b3b9de8cf3241ab8dd97892f0ad3cf
$ echo "1st hello world" | commit-tree 937b5d80b2b3b9de8cf3241ab8dd97892f0ad3cf
Committing initial tree 937b5d80b2b3b9de8cf3241ab8dd97892f0ad3cf
d2970ed409efe53434b0bff727cc5bc0b56b4958

作成したcommitオブジェクトはSHA1ハッシュd2970ed409efe53434b0bff727cc5bc0b56b4958で管理される。

リポジトリの状態

1stコミット直後のリポジトリの状態

1stコミット後のリポジトリ

ここまでは前回と同様である。

2ndコミット

ファイルを修正し2ndコミットを行いリポジトリ内部を確認する

ファイルアップデート

src/world.shの内容をアップデートする。

確認に利用するファイル内容を修正する
$ echo 'echo "World, v2"' > src/world.sh
$ cat src/world.sh
echo "World, v2"

コミット

アップデートしたsrc/world.shを登録し、write-treeコマンドとcommit-treeコマンドで2ndコミットを行う。

2ndコミットを行う
$ update-cache src/world.sh
$ write-tree
c7cfa281da8793c504aea1c515d2e9b12522cbf4
$ echo "2st hello world" | commit-tree c7cfa281da8793c504aea1c515d2e9b12522cbf4
Committing initial tree c7cfa281da8793c504aea1c515d2e9b12522cbf4
f6462e93a04c17443d782550cb20b06a354a4815

update-cacheコマンドにはsrc/world.shしか引数として渡していないが、indexファイルには元のREADME.md, src/hello.sh, そして修正した後のsrc/world.shblobオブジェクトへのSHA1ハッシュが保存されている。つまり、一度indexファイルに登録したファイルは今後の全てのコミットの対象になるファイルだとして取り扱われる。
この動作は最新のgitの挙動と同一であると言えるだろう。

リポジトリの状態

2ndコミットの対象としたtreeオブジェクトの内容を確認する。
README.mdファイルとsrc/hello.shファイルに対しては、1stコミットのtreeオブジェクトから指していた既存のblobオブジェクトを指しており、src/world.shファイルについては、さきほどupdate-casheコマンドで新規に作成したblobオブジェクトを指している。

read-tree c7cfa281da8793c504aea1c515d2e9b12522cbf4
100664 README.md (5f60b55715af0273fd592428a179c59299a0987f)
100664 src/hello.sh (c1e79ffabce97edb43548eae29e3b4a1b6fe9071)
100600 src/world.sh (616ca6f7edce8c4f755aa8344cee6383f9d780d5)

つまり、変更があったファイルについてのみ指すblobオブジェクトを変更している。
そのblobオブジェクトは変更後のファイルをzlibで圧縮したファイルである。

スクリーンショット 2024-01-07 20.52.22.png

非常にシンプルな仕組みでコミットを実現していることがわかる。
ファイルの変更があった場合にその変更箇所を保存するようなCVSSubversionといった伝統的なSCM(Source Control Management)とは異なり、変更のあったファイルを そのまま 保存する。差分が必要な場合は動的に差分ファイルを作成する。このような挙動をとるため、gitのコミットはスナップショットであり差分ではない、と言われたりする。
gitからSCMに触れた人には当たり前の話なのだが、古いSCMに慣れたエンジニアからするとコミットはスナップショットと言われるとその仕組を理解したくなるくらいには衝撃的である。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1