Gitの中身を読んでみる

 

この記事について

本記事は、2022年5月に実施した社内勉強会資料の内容をもとに、社外向けに再編集したものです。
記載の情報は執筆当時のものであり、現在の仕様や価格とは異なる可能性があります。
実装にあたっては、必ず最新の公式ドキュメントをご確認ください。


 はじめに

Gitリポジトリの仕組みを一度確認しておきましょう。 

目次

公式ドキュメント

公式ドキュメントを読みましょう。

Git は内容アドレスファイルシステムです。 素晴らしい。 …で、それはどういう意味なのでしょう?

出典:Git – Gitオブジェクト – 10.2 Gitの内側  https://git-scm.com/book/ja/v2/Git%e3%81%ae%e5%86%85%e5%81%b4-Git%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88

Gitリポジトリの中身を見てみる

下記スクリプトでgitリポジトリを作成します。

git init
echo '1' >> a.txt
git add a.txt  
git commit -m '1'

 

 

作成したgitリポジトリの様子です。

PS C:\Users\sampleuser\work\20220518> > git log
commit 9bd345b034f0b988aa83f263a72110dcec7171f1 (HEAD -> main)
Author: sample-user-ops-in <sample@test.com>
Date:   Wed May 18 21:57:20 2022 +0900

1

 

 

コミットのshaを指定して中身を見ることができます。

ツリー tree というものを含んでいることがわかります。

PS C:\Users\sampleuser\work\20220518> > git cat-file -p 9bd345
tree 512629789217105b3c6e6a0bfd3be3ee0db3bea1
author sample-user-ops-in <sample@test.com> 1652878640 +0900
committer sample-user-ops-in <sample@test.com> 1652878640 +0900

1

 

 

では、ツリーのshaを指定して中身を見てみます。

rw-r—r— a.txtというブロブ blob を含んでいることがわかります。

これはディレクトリに対応するもののようです。

PS C:\Users\sampleuser\work\20220518> > git cat-file -p 512629
100644 blob ca9053508c38ce794241a50d536ce683f2f662f4    a.txt

 

さらに、ブロブのshaを指定して中身を見ることができます。

これはファイルに対応するもののようですが。。あれ?何かゴミが。。

PS C:\Users\sampleuser\work\20220518> > git cat-file -p ca9053
ÿþ1

 

↑UTF-16 CRLFになってたみたいです。。。しばらくこのまま進みます。

(原因は、Windows PowerShellでechoを使ったからだと思います。。ここからはgit bash)

 

ここまでで、コミット、ディレクトリ、ファイルに対応するgitオブジェクトをコマンドで確認してきました。

これらは全て.git/objects以下に格納されており、これらのファイルさえあればGitリポジトリを復元できます。

$ find .git/objects/ -type f                                                                                                                
.git/objects/51/2629789217105b3c6e6a0bfd3be3ee0db3bea1
.git/objects/9b/d345b034f0b988aa83f263a72110dcec7171f1
.git/objects/ca/9053508c38ce794241a50d536ce683f2f662f4

 

例えば下記の手順で、gitリポジトリを複製できることがわかります。

$ mkdir ../clone

sampleuser@DESKTOP-5STAD90 MINGW64 ~/work/20220518 (main)
$ cp -rp .git ../clone/
$ cd ../clone
$ git restore .
$ git status
On branch main
nothing to commit, working tree clean

$ cat a.txt
□□1

 

 

Gitリポジトリの履歴の中身を見てみる

 

別のディレクトリで、新しいgitリポジトリを作ります。

git init
echo '111111' >> README.md
git add README.md
git commit -m 'commit 1'

echo '222222' >> README.md
git add README.md
git commit -m 'commit 2'

echo '333333' >> README.md
git add README.md
git commit -m 'commit 3'

 

作成したリポジトリの様子です。

$ ll
total 1
-rw-r--r-- 1 sampleuser 197121 21  5月 18 23:11 README.md

$ cat README.md 
111111
222222
333333

 

$ git log --graph
* commit 349f23cbe3b974641e5c23e3554d9214c4b528f7 (HEAD -> main)
| Author: sample-user-ops-in <sample@test.com>
| Date:   Wed May 18 23:11:22 2022 +0900
|
|     commit 3
|
* commit 56bf1ff386122893942cd44c1c4cc8e42c87cc78
| Author: sample-user-ops-in <sample@test.com>
| Date:   Wed May 18 23:11:08 2022 +0900
|
|     commit 2
|
* commit 0fe3c14395fac19bc6ce41323e1a6d8574c43f3e
  Author: sample-user-ops-in <sample@test.com>
  Date:   Wed May 18 23:10:52 2022 +0900

      commit 1

 

最新のコミットの中身を見てみましょう。

さっきと違って、親コミット parent を含んでいますね。

$ git cat-file -p 349f23
tree 056ae2bf328865d5bb81837356c4d4f47c7c1d38
parent 56bf1ff386122893942cd44c1c4cc8e42c87cc78
author sample-user-ops-in <sample@test.com> 1652883082 +0900
committer sample-user-ops-in <sample@test.com> 1652883082 +0900

commit 3

 

ツリーの中身を見てみます。

$ git cat-file -p 056ae2
100644 blob 2928adc6d76345d3321371fdc4f9032e8c2d1318    README.md

$ git cat-file -p 2928ad
111111
222222
333333

 

一つ前のコミットの中身も見てみます。

ちゃんと全部の内容が保存されていますね。

$ git cat-file -p 
56bf1f
tree d7e6795d61832d0e482db10efee64f96b41967d2
parent 0fe3c14395fac19bc6ce41323e1a6d8574c43f3e
author sample-user-ops-in <sample@test.com> 1652883068 +0900
committer sample-user-ops-in <sample@test.com> 1652883068 +0900

commit 2

sampleuser@DESKTOP-5STAD90 MINGW64 ~/work/20220518 (main)
$ git cat-file -p d7e6795
100644 blob 06ec666af482db71330230038dc27e35320c6f59    README.md

sampleuser@DESKTOP-5STAD90 MINGW64 ~/work/20220518 (main)
$ git cat-file -p 06ec666
111111
222222

 

Gitはファイルの差分計算をしているのではなく、下記を保存していることがわかります。

  • 今までの全てのコミット
  • 今までにコミットした全てのディレクトリの状態(ツリー)
  • 今までにコミットした全てのファイルの状態(ブロブ) 

ブランチとは結局何なのか

ブランチとは、あるコミット(sha)を指すもの。ただそれだけの単純なものです。

下にある349f23c..は、先ほどの最新コミットのshaですね。

$ git branch -v
* main 349f23c commit 3

 

これも.gitに入っています。

$ cat .git/refs/heads/main 
349f23cbe3b974641e5c23e3554d9214c4b528f7

同じ内容のファイルは同じshaのブロブになる

公式ドキュメントに、ブロブ等の具体的なエンコード法とsha計算が記載されています。

出典:Git – Gitオブジェクト – 10.2 Gitの内側
https://git-scm.com/book/ja/v2/Gitの内側-Gitオブジェクト

git gc

 手動で実行することも可能です。

(おまけ)特定のファイルだけ、ローカルの変更を無視したい

無視する

$ git update-index --skip-worktree config/environments/development.rb
$ git ls-files -v | grep ^S
S config/environments/development.rb

 

戻す

$ git update-index --no-skip-worktree config/environments/development.rb
$ git ls-files -v | grep ^S

まとめ

  • Gitリポジトリの構造は非常にシンプルなので、通常の操作で問題が発生しても、大抵は通常の操作で解決できます。
  • ブランチとは、特定のコミットを指し示すポインタです

参考サイト

出典:Git – Gitオブジェクト – 10.2 Gitの内側
https://git-scm.com/book/ja/v2/Gitの内側-Gitオブジェクト

役に立ったらシェアしていただけると嬉しいです
  • URLをコピーしました!
  • URLをコピーしました!
目次