この記事について
本記事は、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オブジェクト