Slide 1

Slide 1 text

©MIXI ©MIXI MIXI 24新卒技術研修 Git研修 Basic

Slide 2

Slide 2 text

22 ©MIXI 講師紹介 久⽥ 将成 ひさだ まさなり 2022年度新卒⼊社 ライブエクスペリエンス事業本部 ファンコミュニケーション部 Fansta開発グループ 業務: Ruby on Rails 、Next.js 、Flutter など 趣味: Rust など 好きなGitコマンド: git rebase 得意なこと: コンフリクトを起こすこと、夜更かし 苦⼿なこと: コンフリクトの解消、早起き

Slide 3

Slide 3 text

33 ©MIXI 講師紹介 登内 雅⼈ とのうち まさと 2020 年度新卒⼊社 • 業務:開発本部 たんぽぽ室 たんぽぽグループ • ML系の研究開発やバックエンドを主に担当 • Python、Go、Flutter、Ruby • 趣味:格闘技、将棋、ポーカーとかにハマってる • 好きなGitコマンド:git push -f github pages: https://github.com/tonouchi510

Slide 4

Slide 4 text

4 ©MIXI タイムテーブル(予定) 10:30 - 12:00 Git研修 Basic (基礎 / 内部構造) 12:00 - 13:00 お昼休憩 13:00 - 16:30 Git Challenge 16:40 - 18:30 Git研修 Advanced(チーム開発について)

Slide 5

Slide 5 text

5 ©MIXI ⽬次 1. Gitとは 2. Gitの基本的な使い⽅ 3. ブランチの使⽤ 4. 歴史の改変 5. その他便利機能 基礎編 1. Gitオブジェクト 2. コミットの仕組み 3. resetの仕組み 内部構造編

Slide 6

Slide 6 text

©MIXI Gitとは

Slide 7

Slide 7 text

7 ©MIXI Gitとは Gitはバージョン管理システム(VCS)

Slide 8

Slide 8 text

8 ©MIXI Gitとは 例えばファイル名を使ったバージョン管理 書類_最新.pdf 書類_修正版.pdf 書類_最終.pdf 書類_提出⽤.pdf 書類.pdf 書類(1).pdf あるいは 書類_0402_2.pdf 書類_0403.pdf 書類_0403_2.pdf 書類_0403_3.pdf 書類_0401.pdf 書類_0402.pdf

Slide 9

Slide 9 text

9 ©MIXI Gitとは 例えばファイル名を使ったバージョン管理 書類_最新.pdf 書類_修正版.pdf 書類_最終.pdf 書類_提出⽤.pdf 書類.pdf 書類(1).pdf 最新の版は? ひとつ前の版は? 複数⼈で扱うにはちょっと苦しい

Slide 10

Slide 10 text

10 ©MIXI Gitとは Gitを使⽤したバージョン管理 書類.pdf 04/02 15:00 書類.pdf 04/03 10:00 書類.pdf 04/01 12:00 書類.pdf 04/02 13:00 最新版 初稿 差分が出せたり 好きな版に戻れたり この他にもチーム開発に便利な機能がたくさん!

Slide 11

Slide 11 text

11 ©MIXI Gitとは 現代のソフトウェア開発における デファクトスタンダードが Git 今やバージョン管理に留まらず ⾃動化されたテストやビルド:CI ⾃動化されたデプロイ:CD の基盤としても使われている Continuous Integration Continuous Delivery

Slide 12

Slide 12 text

©MIXI Gitの基本的な使い⽅

Slide 13

Slide 13 text

13 ©MIXI Gitの基本的な使い⽅ はじめにリポジトリ(repository)を作る Gitでバージョン管理したいディレクトリに移動してから $ git init 以下のように表⽰されたら成功! Initialized empty Git repository in ディレクトリパス このディレクトリ内がGitが管理する範囲になり、これをリポジトリと呼ぶ ちなみに 既存のリポジトリで作業を始める場合はクローン(clone)する $ git clone リポジトリURL 参照: git-init Documentation git-clone Documentation もっとちなみに リポジトリ直下には .git というディレクトリが作られる 詳しくは内部構造編で!

Slide 14

Slide 14 text

14 ©MIXI Gitの基本的な使い⽅ Gitでは「コミット(commit)」という単位で変更を保存する 書類.pdf 04/01 12:00 コミット 書類.pdf 04/02 13:00 コミット 書類.pdf 04/02 15:00 コミット 変更をコミット対象にする(ステージング) ステージングした変更でコミットする $ git add ファイル名 $ git commit 書類.pdf 04/03 10:00 コミット 全部なら -A オプション 参照: git-add Documentation git-commit Documentation

Slide 15

Slide 15 text

15 ©MIXI Gitの基本的な使い⽅ 変更をコミットするまでの段階はこんな感じ ワーキングディレクトリ ファイルを編集した状態 ステージングエリア ステージングされた状態 コミット コミットされた状態 $ git add $ git commit 各ファイルがどの段階にあるかを確認するには $ git status 参照: git-status Documentation

Slide 16

Slide 16 text

16 ©MIXI Gitの基本的な使い⽅ コミットログを⾒てみる $ git log --oneline --graph bca877d40 最初のコミット 6aa4aa7ae 2番⽬のコミット 4e62a7326 3番⽬のコミット コミットID コミットメッセージ コミットIDはコミットを⼀意に識別するID コマンド内でコミットを指定する場合に使ったりする 例えばコミットの詳細を⾒るには $ git show コミットID 他にもコミット間の差分を⾒るには $ git diff コミットID1 コミットID2 ちなみに 最後に ^ をつけるとその1つ前のコミット、 HEAD を指定すると今いるコミットを⽰す [HEAD] もっとちなみに 参照: git-log Documentation git-show Documentation git-diff Documentation コミットID部分は正確には参照(refs)も可 後述するブランチとかタグとか

Slide 17

Slide 17 text

17 ©MIXI Gitの基本的な使い⽅ コミットをリモートリポジトリにプッシュ(push: アップロード)したり、 コミットをリモートリポジトリからプル(pull: ダウンロード)することで変更を共有する Push Pull Pull Push コミットをプッシュする コミットをプルする $ git push $ git pull 参照: git-push Documentation git-pull Documentation

Slide 18

Slide 18 text

18 ©MIXI Gitの基本的な使い⽅ 別のコミットに戻りたいときはチェックアウト(checkout) $ git checkout コミットID $ git switch コミットID --detach もしくは EXPERIMENTAL ファイルを別のコミット時点に戻したいときもチェックアウト $ git checkout コミットID ファイル名 $ git restore ファイル名 -s コミットID EXPERIMENTAL もしくは 参照: git-checkout Documentation git-switch Documentation Git - git-restore Documentation

Slide 19

Slide 19 text

19 ©MIXI Gitの基本的な使い⽅ コミットを打ち消したいときはリバート(revert) 指定したコミットと逆のコミットを追加する 1 Hello, World! 2 1 Hello, World! 2 Hello, MIXI! 3 MIXIを追加 1 Hello, World! 2 Hello, MIXI! 3 revert Revert コミットをリバートする $ git revert コミットID 参照: git-revert Documentation

Slide 20

Slide 20 text

20 ©MIXI Gitの基本的な使い⽅ タグ(tag)機能を使うと特定のコミットに⽬印を付けられる $ git tag タグ名 コミットID version1.2 version1.1 version1.0 リリースしたらバージョン名のタグを作る運⽤も多い印象 タグ名はコミットIDと同じように使える $ git switch タグ名 --detach $ git show タグ名 タグのついたコミットに移動するなら タグのついたコミットの詳細を⾒るなら 参照: git-tag Documentation

Slide 21

Slide 21 text

©MIXI ブランチの使⽤

Slide 22

Slide 22 text

22 ©MIXI ブランチの使⽤ 複数の開発を並⾏して⾏うためにブランチ(branch)という機能がある 複数のブランチで開発を進めて、それらをマージ(merge)することで成果物を作る 機能B 機能A ブランチ マージ

Slide 23

Slide 23 text

23 ©MIXI main develop ブランチの使⽤ まずは develop という名前でブランチを作ってみる $ git branch develop bca877d40 Commit 1 最初はmainやmasterという名前のブランチが作られている ブランチの⼀覧を確認してみる $ git branch * main develop 参照: git-branch Documentation

Slide 24

Slide 24 text

24 ©MIXI develop ブランチの使⽤ まずは develop という名前でブランチを作ってみる $ git branch develop bca877d40 Commit 1 main 最初はmainやmasterという名前のブランチが作られている ブランチの⼀覧を確認してみる $ git branch * main develop develop ブランチに移動してみる $ git checkout develop または $ git switch develop develop 今いるブランチを確認してみる $ git branch main * develop 参照: git-branch Documentation

Slide 25

Slide 25 text

25 ©MIXI ブランチの使⽤ コミットを追加してみる $ git commit 2a673e714 Commit 1 main f20100b9e Commit on develop develop

Slide 26

Slide 26 text

26 ©MIXI ブランチの使⽤ コミットを追加してみる $ git commit 2a673e714 Commit 1 main f20100b9e Commit on develop develop 2f8ff17f6 Commit on main main 仮にmainにコミットが増えるとこうなる

Slide 27

Slide 27 text

27 ©MIXI ブランチの使⽤ マージ先ブランチに移動する $ git checkout main 2a673e714 Commit 1 f20100b9e Commit on develop develop develop main 参照: git-merge Documentation 2f8ff17f6 Commit on main

Slide 28

Slide 28 text

28 ©MIXI ブランチの使⽤ マージ先ブランチに移動する $ git checkout main 2a673e714 Commit 1 f20100b9e Commit on develop develop マージする $ git merge develop develop 95e9ea33b Merge branch ‘develop’ main マージコミット 参照: git-merge Documentation

Slide 29

Slide 29 text

29 ©MIXI ブランチの使⽤ マージの際、両ブランチの変更内容は⾃動でいい感じに混ぜられる 1 Hello, World! 2 and 3 Hello, MIXI! 4 1 Hi, World! 2 and 3 Hello, MIXI! 4 1 Hello, World! 2 and 3 Yeah, MIXI! 4 1 Hi, World! 2 and 3 Yeah, MIXI! 4

Slide 30

Slide 30 text

30 ©MIXI ブランチの使⽤ じゃあ、これは? 1 Hello, World! 2 1 Hello, e-Mercury! 2 1 Hello, MIXI! 2

Slide 31

Slide 31 text

31 ©MIXI ブランチの使⽤ マージしてみると怒られる Auto-merging hello.txt CONFLICT (content): Merge conflict in hello.txt Automatic merge failed; fix conflicts and then commit the result. (以下意訳) hello.txt のマージでコンフリクトが起きたよ。 ⾃動マージが失敗しちゃったからコンフリクトを直してからコミットしてね。 このように⾃動マージに失敗した状況をコンフリクト(conflict: 競合)と呼ぶ コンフリクトが発⽣した場合は⼿動マージが必要

Slide 32

Slide 32 text

32 ©MIXI ブランチの使⽤ 直してみる 問題のファイルを開くとこうなっている 1 <<<<<<< HEAD 2 Hello, e-Mercury! 3 4 ======= 5 Hello, MIXI! 6 >>>>>>> mixi コンフリクトーマーカー HEAD(今いるところ)の変更内容 ブランチ mixi の変更内容 これをあるべき姿に直してコミットすればよい

Slide 33

Slide 33 text

33 ©MIXI ブランチの使⽤ 例えば Hello, MIXI! を残すならこうする 1 Hello, MIXI! 2 もしくは両⽅残すならこうする 1 Hello, e-Mercury! 2 Hello, MIXI! 3 忘れずに add してコミットすれば⼿動マージ完了! $ git add hello.txt $ git commit ちなみに $ git status でコンフリクトしているファイルの⼀覧が確認できる たくさんある場合は直したファイルから add していくのがおすすめ

Slide 34

Slide 34 text

34 ©MIXI ブランチの使⽤ マージは⾏ごとに処理されるのでこの場合もコンフリクトが起きる 1 Hello, World! 2 1 Hi, World! 2 1 Hello, MIXI! 2 1 <<<<<<< HEAD 2 Hi, World! 3 4 ======= 5 Hello, MIXI! 6 >>>>>>> mixi 1 Hi, MIXI! 2

Slide 35

Slide 35 text

35 ©MIXI ブランチの使⽤ コンフリクトはできるだけ避けたくはあるものの、起こるときは起こる ⼿動マージは間違いやすいので注意して作業しよう それぞれのブランチで加えられた変更の意図を理解するのが近道 merge-base コマンドで分岐元が調べられる $ git merge-base main develop 分岐元からの差分を⾒たり…… 含まれるコミットメッセージやPull requestを読んだり…… ⼤変だけど間違うともっと⼤変なので頑張ろう 参照: git-merge-base Documentation

Slide 36

Slide 36 text

36 ©MIXI ブランチの使⽤ ところで fast-forward というマージがある この状態で develop を main にマージすると…… 2a673e714 Commit 1 f20100b9e Commit on develop develop main develop $ git merge develop

Slide 37

Slide 37 text

37 ©MIXI ブランチの使⽤ ところで fast-forward というマージがある この状態で develop を main にマージすると…… こうなる 2a673e714 Commit 1 f20100b9e Commit on develop develop main develop $ git merge develop main

Slide 38

Slide 38 text

38 ©MIXI main ブランチの使⽤ マージ対象ブランチの⽚⽅のみに変更がある場合、マージコミットは必須でない マージ先ブランチをマージ元ブランチの位置に移動することで 通常のマージと同じ結果を得られる これを fast-forward(早送り) と呼ぶ 2a673e714 Commit 1 f20100b9e Commit on develop develop main develop

Slide 39

Slide 39 text

39 ©MIXI ブランチの使⽤ デフォルトだと可能な限りfast-forwardするようになっている fast-forward しないようにするなら 逆にfast-forwardを強制するなら fast-forwardマージはコミットログがシンプルになる⼀⽅、マージした形跡が残らない 作りたいコミットログやチームの⽂化によって使い分けられるようになろう $ git merge develop --no-ff $ git merge develop --ff-only main 2a673e714 Commit 1 f20100b9e Commit on develop develop main develop

Slide 40

Slide 40 text

©MIXI 歴史の改変

Slide 41

Slide 41 text

41 ©MIXI 歴史の改変 ここまではコミットログにコミットを追加していく操作を紹介してきたが、 コミットログを改変することも可能 必然的に破壊的な操作も多くなるので注意深く使⽤すること

Slide 42

Slide 42 text

42 ©MIXI 歴史を改変してみる前にコミットログの構造を少し説明したい 歴史の改変 コミットは1つ前がどのコミットかを知っている(参照を持っている) bca877d40 最初のコミット 6aa4aa7ae 2番⽬のコミット 4e62a7326 3番⽬のコミット [HEAD] 新 古 つまり…… 参照 参照 新しいコミットから古いコミットは辿れる 古いコミットから新しいコミットは辿れない コミットの削除とはそのコミットが どこからも辿れなくなることを意味する ちなみに 加えて今いるところ(HEAD)や ブランチの先端のコミットを別途保存することで コミットログが描画できる

Slide 43

Slide 43 text

43 ©MIXI 歴史の改変 最近のコミットをなかったことにするならリセット(reset) $ git reset コミットID よく使うオプションは以下 HEAD HEAD 削除 --soft --mixed(デフォルト) --hard :変更はステージングされた状態で残す :変更はステージングされていない状態で残す :変更は破棄する 変更をステージングしたけどやっぱりやめたいときもresetを使う $ git reset . 参照: git-reset Documentation

Slide 44

Slide 44 text

44 ©MIXI 歴史の改変 操作を間違えたら reflog で復旧できる……かも $ git reflog aec805a (HEAD -> main) HEAD@{0}: reset: moving to head^^ 561f0de HEAD@{1}: commit: Important commit 2 11dd662 HEAD@{2}: commit: Important commit aec805a (HEAD -> main) HEAD@{3}: commit: Add new file. 74c7044 HEAD@{4}: commit (initial): First commit 操作の結果移動した先のコミット 操作の内容 以下はresetで最新のコミットを2つ消し⾶ばした時のreflog この場合は reset する前にいたコミット 561f0de に再び reset することでもとに戻せる $ git reset 561f0de 参照: git-reflog Documentation

Slide 45

Slide 45 text

45 ©MIXI 歴史の改変 ブランチ上で作業していて分岐元のブランチが進んでしまった時は リベース(rebase)で追従するのが便利 歴史を改変するのが怖ければ代わりにマージしても同じ結果が得られるが リベースの⽅がコミットログはシンプルになる HEAD main $ git rebase --continue もしコンフリクトしたら解決後に continue で続⾏できる HEAD 参照: git-rebase Documentation $ git rebase main

Slide 46

Slide 46 text

46 ©MIXI 歴史の改変 もっと⼤胆に歴史を変えるならリベースのインタラクティブモード 指定したコミットの次のコミット以降を対象にいろいろできる $ git rebase -i コミットID HEAD このコミットを指定すると この範囲が対象になる

Slide 47

Slide 47 text

47 ©MIXI 歴史の改変 よく使うのはコミットをまとめる squash 前のコミットに吸収される w ork1 w ork2 w ork3 pick 56da94f work1 pick 4a1d066 work2 pick f908cb9 work3 pick 56da94f work1 squash 4a1d066 work2 squash f908cb9 work3 w ork1, 2, 3

Slide 48

Slide 48 text

48 ©MIXI 歴史の改変 他にもいろいろできるので⼀部抜粋して紹介 reword edit :コミットをそのまま残す :コミットメッセージを書き直す :コミットを編集する pick(デフォルト) fixup exec squash :コミットを前のコミットとまとめる(前述) :squashっぽいけどメッセージはそのコミットのものを採⽤する :任意のコマンドを実⾏する ⾏を並べ替えるとコミットが並べ替えられたり…… ⾏を削除するとコミットが削除できたり…… 開いたエディタにできることが書いてあるので⼀度読んでみるとよい

Slide 49

Slide 49 text

49 ©MIXI 歴史の改変 ところでリモートリポジトリにプッシュする際、通常はコミットの追加のみが許される

Slide 50

Slide 50 text

50 ©MIXI 歴史の改変 過去のコミットを変更してプッシュしようとすると弾かれる 削除

Slide 51

Slide 51 text

51 ©MIXI 歴史の改変 これをプッシュするには強制プッシュが必要 $ git push --force (-f) 削除 削除 もし他の⼈がコミットをプッシュしていたらそのコミットは消えてしまう

Slide 52

Slide 52 text

52 ©MIXI 歴史の改変 これを他のメンバーがプルするとこちらもまた弾かれる こうなると結構めんどくさい ⾃分の変更を退避して…… 強制プルして…… コミットし直して…… みたいになる 基本的に⼈と共有しているブランチへの強制プッシュは避けたほうが無難 削除 削除

Slide 53

Slide 53 text

53 ©MIXI 歴史の改変 多くの⼈で共有している⼤事なブランチは リモートリポジトリ側で強制プッシュを禁⽌する設定をしておくべき(ブランチ保護) とはいえ⾃分のブランチへの操作を誤ってひとりで悲しい思いをするのも切ないので ⽐較的安全な強制プッシュを覚えておこう --force-with-lease: リモートリポジトリ側のコミットログに知らない変更があればプッシュを中⽌する $ git push --force-with-lease --force-if-includes --force-if-includes: リモートリポジトリ側の最新のコミットに触った形跡がなければプッシュを中⽌する 超ざっくり解説 強制プッシュはいつもこれを使うくらいのつもりで問題ない 正確な説明は公式ドキュメントへ! https://git-scm.com/docs/git-push

Slide 54

Slide 54 text

©MIXI その他便利機能

Slide 55

Slide 55 text

55 ©MIXI commit コマンドの --amend オプション 直前のコミットを上書きしてコミットする 他にも便利な機能があるので紹介しておく(その1) その他便利機能 submodule 参照: Git - Submodules リポジトリ内に別のリポジトリを内包できる cherry-pick 参照: git-cherry-pick Documentation 指定したコミットと同じ内容のコミットを今いるブランチに追加する stash 参照: git-stash Documentation コミットしていない変更を⼀時的に退避できる -(ハイフン) 1つ前にいたブランチを⽰す(例: $ git switch - で1つ前のブランチに戻る)

Slide 56

Slide 56 text

56 ©MIXI hooks 参照: Git Hooks 指定した操作の前や後に任意の処理を実⾏したりできる 他にも便利な機能があるので紹介しておく(その2) その他便利機能

Slide 57

Slide 57 text

57 ©MIXI add -A: すべての変更をステージする -p: 変更を部分的にステージする commit -a: すべての変更をステージしてからコミットする -m ’メッセージ’: コミットメッセージをオプションで渡せる(エディタが開かない) -n: pre-commit, commit-msg hooks を無視する log --graph: コマンドライン上でグラフィカルに表⽰する --oneline: 1コミット1⾏で表⽰する --all: 今いるブランチ以外のコミットも表⽰する よく使うかもしれない細かいオプションとか(その1) その他便利機能

Slide 58

Slide 58 text

58 ©MIXI checkout -b ブランチ名: ブランチを作ってそこに移動する switch -c ブランチ名:ブランチを作ってそこに移動する merge --abort: コンフリクトでマージが中断したときに、マージを中⽌する よく使うかもしれない細かいオプションとか(その2) その他便利機能

Slide 59

Slide 59 text

©MIXI ©MIXI MIXI 24新卒技術研修 Git研修 内部構造

Slide 60

Slide 60 text

60 ©MIXI Git の内部構造を学ぶ意義 Git ⾃体は内部を知らなくとも⼗分使える優秀なツール ● Git のサブコマンドが実際どういった挙動をしているのか ● 内部構造がどうなっているか これらを知らなくとも⼗分使えるため、学んだことがある⼈は少ないかもしれない ⼀⽅で、仕組みや内部構造を知ることで以下のような利点がある ● 毎回調べながら Git を使うという状況を脱せる ● Git を使っていて何らかの問題が起きたときに⾃⼒で解決できる

Slide 61

Slide 61 text

61 ©MIXI Git の内部構造を学ぶ意義 Git を使っていてこんな経験はないか? ● ブランチをマージ前に間違えて消してしまった! ● コミットを誤って消してしまった! ● コミット前(ステージングエリア)のファイルを消してしまった! 内部構造を学ぶことでこれらの問題に、⾃⼒で対処できるようになる。

Slide 62

Slide 62 text

62 ©MIXI Gitについての誤解 Git の内部構造を知る前だと、(僕も含め)各コマンドに対する印象は例えば以下のような イメージになるかもしれない。 1. commit とは、 ○ add の操作を確定するもの? ○ 親 commit との差分を保存しているもの? 2. branch とは、 ○ 分岐した時点以降のコミットのこと? 3. reset とは、 ○ add や commit を無かったことにできるコマンド? ○ ファイルの変更を無かったことにできるコマンド?

Slide 63

Slide 63 text

63 ©MIXI Gitについての誤解 => 全て間違い(厳密には) Git について、多くの⼈が誤解しているであろうポイントを紹介しました。 これらの実態が分かれば、誤った操作をしてしまった時に焦る必要がないことが分かるよ うになると思います。 ここからは、Git がどのようにしてバージョン管理を実現しているかを理解するために、内 部構造を紐解いていきます。具体的には、.gitディレクトリの中⾝について取り扱っていき ます。 git init した時に できるあれ

Slide 64

Slide 64 text

64 ©MIXI .git ディレクトリ ⼿元の適当な .gitディレクトリ の中を眺めてみてください もしなければ以下のリポジトリをクローンして使ってください => https://github.com/mixigroup/sample_repository $ git clone [email protected]:mixigroup/sample_repository.git $ ls .git/objects info pack # packfileを解凍する $ mkdir temp && cd temp $ git init $ git unpack-objects < ../sample_repository/.git/objects/pack/pack-147de79371a5b4f88389ef990099a091983da7f8.pack $ find .git/objects -not -name 'pack' -a -not -name 'info' -type d -mindepth 1 | xargs -I {} mv {} ../sample_repository/.git/objects/ $ cd ../sample_repository 最初はPackfileに圧縮 されてしまっている Packfileについて興味 ある⽅はこちら

Slide 65

Slide 65 text

65 ©MIXI .git ディレクトリ とりあえず ls して中⾝を⾒てみる まずは objects ディレクトリを⾒ていく 中にさらにサブディレクトリがあり、その中にファイルがある => Gitオブジェクト $ ls .git COMMIT_EDITMSG HEAD config description hooks index info logs objects packed-refs refs $ ls .git/objects 2c 2e 2f 3e 3f 5e 63 77 7c 9c 9d a3 aa b4 b6 bc bd c6 f7 f9 info pack $ ls .git/objects/2c/ 14dff3277ae4751173f3c26802620de960aaa1

Slide 66

Slide 66 text

©MIXI Git オブジェクト

Slide 67

Slide 67 text

67 ©MIXI Git オブジェクト Git はバージョン管理に必要なデータを主に「オブジェクト」と呼ばれる概念で表現し、 `.git/objects`ディレクトリで管理しています。 オブジェクトは以下の4種類 ● blob オブジェクト ○ ファイルの情報が⼊っているオブジェクト(バックアップ) ● tree オブジェクト ○ ディレクトリ情報が⼊っているオブジェクト ● commit オブジェクト ○ コミットの情報が⼊っているオブジェクト ● tag オブジェクト ○ annotated tag の情報が⼊っているオブジェクト ○ 重要度が低いので省略 => 興味がある⼈はこちらを参照してください

Slide 68

Slide 68 text

68 ©MIXI Git オブジェクト Git はこれらのオブジェクトを Key-Value Store として管理している。 1. それぞれのオブジェクト(Value)を作成 2. オブジェクトの中⾝を SHA-1 ハッシュ化した値をKeyとする 3. オブジェクトを zlib 圧縮した上で、.git/objects/以下に Key をファイル名として保存 ○ 検索効率性のために、Key の先頭2⽂字でサブディレクトリを切る $ ls .git/objects 2c 2e 2f 3e 3f 5e 63 77 7c 9c 9d a3 aa b4 b6 bc bd c6 f7 f9 info pack $ ls .git/objects/2c/ 14dff3277ae4751173f3c26802620de960aaa1 ※SHA-1:https://ja.wikipedia.org/wiki/SHA-1 ※Zlib:https://ja.wikipedia.org/wiki/Zlib

Slide 69

Slide 69 text

69 ©MIXI オブジェクトファイルの基本構成 ● オブジェクトの種類:blob or tree or commit or tag ● オブジェクトのサイズ:数値(単位はbyte) ● オブジェクトのコンテンツ:オブジェクトの種類によってさまざま 最初にオブジェクトの種類やサイズなどのメタデータが記録され、そのあとにコンテンツ が続きます。 これからオブジェクトの種類ごとに、順番に中⾝を⾒ていきます。

Slide 70

Slide 70 text

70 ©MIXI commit オブジェクト commit オブジェクトは、コミットの情報を記録するオブジェクトです。 実際に、Key=bdcc6040408bacfb69727c0f2637bbcec1dbc487 の commit オブジェク トの中⾝を⾒てみます。 そのままだとファイルは zlib 圧縮されているので意味のない⽂字列が表⽰されます。 $ cat .git/objects/bd/cc6040408bacfb69727c0f2637bbcec1dbc487 x��M �0F]�� 2��_ADO"�db �)%�o7^����=>n�

Slide 71

Slide 71 text

71 ©MIXI commit オブジェクト Git オブジェクトの内容を⾒たい場合は、cat-file というサブコマンドを使⽤します。 # tオプションはオブジェクトの種類 $ git cat-file -t c6c63202bf8abde33a80dfc0a230ad1e9791a33b commit # sオプションはオブジェクトのサイズ $ git cat-file -s c6c63202bf8abde33a80dfc0a230ad1e9791a33b 234 # pオプションはオブジェクトの中⾝ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 1670215632 +0900 committer tonouchi510 1670215632 +0900 Add chapter_2.txt

Slide 72

Slide 72 text

72 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 ● リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key) ● 親 commit のハッシュ値 ● committer と author のタイムスタンプ‧名前‧メールアドレス ● コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 1670215632 +0900 committer tonouchi510 1670215632 +0900 Add chapter_2.txt 後ほど解説

Slide 73

Slide 73 text

73 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 ● リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key) ● 親 commit のハッシュ値 ● committer と author のタイムスタンプ‧名前‧メールアドレス ● コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 1670215632 +0900 committer tonouchi510 1670215632 +0900 Add chapter_2.txt

Slide 74

Slide 74 text

74 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 ● リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key) ● 親 commit のハッシュ値 ● committer と author のタイムスタンプ‧名前‧メールアドレス ● コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 1670215632 +0900 committer tonouchi510 1670215632 +0900 Add chapter_2.txt

Slide 75

Slide 75 text

75 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 ● リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key) ● 親 commit のハッシュ値 ● committer と author のタイムスタンプ‧名前‧メールアドレス ● コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 1670215632 +0900 committer tonouchi510 1670215632 +0900 Add chapter_2.txt

Slide 76

Slide 76 text

76 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 ● リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key) ● 親 commit のハッシュ値 ● committer と author のタイムスタンプ‧名前‧メールアドレス ● コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 1670215632 +0900 committer tonouchi510 1670215632 +0900 Add chapter_2.txt これをSHA-1ハッシュ化 したものがKeyになる

Slide 77

Slide 77 text

77 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 ● リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key) ● 親 commit のハッシュ値 ● committer と author のタイムスタンプ‧名前‧メールアドレス ● コミットメッセージ これらのいずれか1つでも変わると、(SHA-1が衝突しない限り)別の commit ハッシュ になる。=> コミットは⼀意に定まる 親コミットのハッシュも含んでいるため、改ざんにも強い。 次に新出の これを解説

Slide 78

Slide 78 text

78 ©MIXI tree オブジェクト treeオブジェクトはディレクトリとしての情報を保持しています。バージョンごとに、Git 管理下の全てのディレクトリに対応する tree オブジェクトが作成されます。 実際に、Key=3f1c1a8a1e11f3147eee31b2bd9f9fb52936f87b のオブジェクトの中⾝を みていきます。 $ git cat-file -t 3f1c1a8a1e11f3147eee31b2bd9f9fb52936f87b tree $ git cat-file -s 3f1c1a8a1e11f3147eee31b2bd9f9fb52936f87b 82 $ git cat-file -p 3f1c1a8a1e11f3147eee31b2bd9f9fb52936f87b 100644 blob bc96df368963ca37edb955c1c0403471b7c90720 chapter_1.txt 100644 blob aaa8bd84e6e4837be33eee9d1ddb9d06d8d2e46c chapter_2.txt

Slide 79

Slide 79 text

79 ©MIXI tree オブジェクト こちらは reports ディレクトリのある時点の tree オブジェクトです。左から順に、 パーミッション、種類、Key、ファイル名が記録されています。 => この tree オブジェクトが作られた時点での、「そのディレクトリに存在したファイ ル」と、「そのバージョンの blobハッシュ値(Key)」 ※(再)blob オブジェクトはファイルの情報が⼊っているオブジェクト $ git cat-file -p 3f1c1a8a1e11f3147eee31b2bd9f9fb52936f87b 100644 blob bc96df368963ca37edb955c1c0403471b7c90720 chapter_1.txt 100644 blob aaa8bd84e6e4837be33eee9d1ddb9d06d8d2e46c chapter_2.txt

Slide 80

Slide 80 text

80 ©MIXI tree オブジェクト 次に、同じバージョンでの、リポジトリのルートディレクトリに対応するtreeオブジェク トも⾒ていきます。 ルートディレクトリにあるファイルの他に、先ほどの reports ディレクトリに関する tree オブジェクトへの参照(Key=3f1c1a8a1e11f3147eee31b2bd9f9fb52936f87b)も保持 していることが分かると思います。 $ git cat-file -p f9ccb461cbfb1837f611b5e31a070945b8cdb867 100644 blob c6c63202bf8abde33a80dfc0a230ad1e9791a33b README.md 040000 tree 3f1c1a8a1e11f3147eee31b2bd9f9fb52936f87b reports 100644 blob 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 test.txt

Slide 81

Slide 81 text

81 ©MIXI tree オブジェクト ルートディレクトリの tree オブジェクトから、順に辿ることでリポジトリの全てのblob オブジェクト(つまり、その時点のファイルの内容)にアクセスすることができます。 このように、Git はファイルシステム になっているのです。 最後に blob オブジェクトについても ⾒ていきます。

Slide 82

Slide 82 text

82 ©MIXI blob オブジェクト blobオブジェクトは、ファイルの実際のバックアップに当たるオブジェクトで、ある時点 (バージョン)でのファイルの情報を記録しています。 この2つはどちらも同⼀ファイル(README.md)の blob オブジェクトで、それぞれ特定 のバージョンに対応する blob オブジェクトとなっています。 ここで重要なのは、blob オブジェクトは「ファイルの差分ではなく、ある時点でのファイ ルの中⾝そのものを記録している」ということです。 => Gitの機能を語る上で重要な要素 $ git cat-file -p f733735eb5e737a9c15756e0556f2155660fa4b0 # git-tutorial-3 $ git cat-file -p c6c63202bf8abde33a80dfc0a230ad1e9791a33b # git-chapter-3 差分が記録されて いるわけではない

Slide 83

Slide 83 text

©MIXI コミットの仕組み

Slide 84

Slide 84 text

84 ©MIXI commit の仕組み ここまで紹介した 3つのオブジェクトに関する内容を踏まえて、コミットの仕組みを解説 していきます。 まずここまでの話を整理すると ● commit オブジェクトは、その時点のリポジトリのルートにあたる tree オブジェクト を参照 ● tree オブジェクトは、その時点の ディレクトリ配下の tree オブジェクトと blob オブ ジェクトへの参照を持つ ● blob オブジェクトは、その時点のファイルのフルバックアップ => commit オブジェクトを参照することで、そこから辿ることで commit 時点のリポジト リの状態を完全に再現できる => スナップショット

Slide 85

Slide 85 text

85 ©MIXI 補⾜ Gitの checkout/switch で、かなり遠い履歴に移る際にも瞬時にリポジトリの状態を復元 できることに驚いた経験はないでしょうか? Gitがファイルを差分で管理しているとしたら、checkout/switch の⾼速な移動は実現で きません。コミットの実態がスナップショットになっていることが⾼速な checkout/switch を可能にしています。 Gitではバージョン間を遷移する際にかかる時間は、履歴の遠さには依存せず、変更された ファイル数に依存します。

Slide 86

Slide 86 text

86 ©MIXI commit の流れ コミットには⼤きく3つの段階があります。 1. コードを編集する 2. 編集したコードをaddする 3. commitする ステップ2で編集したコードを add しています。 この時、Git 内部で⾏われていることを深掘りしていきます。

Slide 87

Slide 87 text

87 ©MIXI index について add について、「コミットに含めたいファイルをステージング(index)に登録してい る」という説明を⾒たことはあるかもしれません。これをもう少し具体的に解説します。 add の説明に⼊る前に、index について解説していきます。 index の情報は .git/index に記録されているので、オブジェクトと同じように⾒ていきま す。 $ cat .git/index DIRCc�[��c�c�[�d:�KCH��S_X�/�S��2����:����0����; README.mdc�b�WF;c�b�Te�KK���S_X�/�S����6�c�7�U��@4q�� reports/chapter_1.txtc�b��uc�b��9KK���S_X�/�S0������ {�>�۝���lreports/chapter_2.txtc�w�2�c�w�2�Ka��S_X�/�S�����L�0U��� �����D�test.txtTREE94 1 �̴a��7��� E�͸greports2 0 ?��~�1�����)6�{�\��(l ����y}8ܗ.cA

Slide 88

Slide 88 text

88 ©MIXI index について バイナリファイルなので、そのまま cat するだけだと⽂字化けしてしまいます。 index の中⾝を⾒るためのサブコマンドも⽤意されているので、そちらを使います。 左から、ファイルの種類+パーミッション、blob ハッシュ、コンフリクトフラグ、ファイ ル名が並んでいます。 index には、現在参照しているバージョン(コミット)で管理対象(ステージングエリア 含め)の全ての blob オブジェクトへの参照をもっています。 $ git ls-files --stage 100644 c6c63202bf8abde33a80dfc0a230ad1e9791a33b 0 README.md 100644 bc96df368963ca37edb955c1c0403471b7c90720 0 reports/chapter_1.txt 100644 aaa8bd84e6e4837be33eee9d1ddb9d06d8d2e46c 0 reports/chapter_2.txt 100644 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 0 test.txt

Slide 89

Slide 89 text

89 ©MIXI add の内部挙動 add した時に起こる内部挙動は、基本的に以下の2点です。 ● blob オブジェクトの⽣成 ● index の更新 実際に add してみていきます。

Slide 90

Slide 90 text

90 ©MIXI add の内部動作 例えば、適当にファイルを作成してaddすると、indexは以下のように更新されています。 temp/hoge.txtがindexに追加されていることがわかります。また、blobハッシュも記録 されており、該当Keyを⾒にいくとblobオブジェクトも⽣成されていることが分かると思 います。 すでにあるファイルを編集した場合も、新しいblobオブジェクトが⽣成され、indexが そのハッシュ値に書き変わります。 $ echo hoge > temp/hoge.txt $ git add temp/hoge.txt $ git ls-files --stage 100644 c6c63202bf8abde33a80dfc0a230ad1e9791a33b 0 README.md 100644 bc96df368963ca37edb955c1c0403471b7c90720 0 reports/chapter_1.txt 100644 aaa8bd84e6e4837be33eee9d1ddb9d06d8d2e46c 0 reports/chapter_2.txt 100644 9c595a6fb7692405a5c4a10e1caf93d7a5bd9c37 0 temp/hoge.txt

Slide 91

Slide 91 text

91 ©MIXI commit の内部挙動 次に、commit した時に起こる内部挙動は、以下の通りです。 ● index から tree オブジェクトを⽣成 ● commit オブジェクトを⽣成 ● HEAD を新しい commit ハッシュに書き換え それぞれ詳しく解説していきます。

Slide 92

Slide 92 text

92 ©MIXI commit の内部挙動 ~tree オブジェクトの作成~ tree オブジェクトの作成はこの段階で⾏われます。 commit すると、新たに作成されたディレクトリに対する tree オブジェクトだけでなく、 リポジトリのルートディレクトリを含むすべてのディレクトリに対する tree オブジェクト の構築処理が動きます。 => index に記録された情報から構築可能 この時、効率化のために index に変更があった部分だけが新しい blob および tree オブ ジェクトに書き換えられ、それ以外の参照が変わらない部分はそのまま流⽤します。

Slide 93

Slide 93 text

93 ©MIXI commit の内部挙動 ~commit オブジェクトの作成~ 新しいルートディレクトリまでの tree オブジェクトが⽣成できたら、次は commit オブ ジェクトを作成します。 commit オブジェクトに記録する情報(再掲) ● リポジトリのルートディレクトリのtreeオブジェクトのハッシュ値(Key) ● 親commitのハッシュ値 ● committerとauthorのタイムスタンプ‧名前‧メールアドレス ● コミットメッセージ 先述の通り、リポジトリのルートにあたるtreeオブジェクトを参照しているため、そこか らリポジトリ全体をたどることができます。

Slide 94

Slide 94 text

94 ©MIXI commit の内部挙動 ~HEAD を新しい commit ハッシュに書き換え~ 最後に、現在参照しているコミットを指す .git/HEAD を必要に応じて書き換えます。 .git/HEAD についても中⾝を⾒てみます。 refs/heads/main(mainブランチ)を参照しているとあるのでそちらを辿って⾒ます。 ここに記録されているのが commit ハッシュです。ここを新しいコミットのハッシュ値 (commit オブジェクトのKey)に書き換えることで、コミット操作を完了します。 $ cat .git/HEAD ref: refs/heads/main $ cat .git/refs/heads/main a311bf20bbd5d272f9286b10dd3c8dc4adc96306

Slide 95

Slide 95 text

95 ©MIXI refs について refs は特定のコミットを指すポインタのようなものです。コミットハッシュのエイリアス とも⾔えます。具体的には以下のものが refs に該当します。 ● tag ○ light-weight tag ○ annotated tag(省略) ● branch ● HEAD(すでにcommitの仕組みで登場)

Slide 96

Slide 96 text

96 ©MIXI refs について ~light-weight tag~ light-weight tag を作成して確認します。タグは .git/refs/tags/ に保存されます。 tag を付与した時点のコミットハッシュが記録されていることがわかると思います。 $ git tag test-1 $ git log -n 1 --oneline bdcc604 (HEAD -> main, tag: test-1) Add chapter_2.txt $ cat .git/refs/tags/test-1 bdcc6040408bacfb69727c0f2637bbcec1dbc487

Slide 97

Slide 97 text

97 ©MIXI refs について ~branch~ 次に branch です。こちらは基本的には light-weight tag と同様です。 違いとしては、保存場所が .git/refs/heads 以下になっている点と、branch の場合はその branch でコミットを実⾏すると、branch が指しているコミットハッシュが⾃動で書き変 わっていくことです。 ※「commitの内部挙動 ~HEADを新しい commit ハッシュに書き換え~」で解説した通り branch の実態も、単に特定のコミットへのポインタなので、branch を削除してしまった としても焦る必要はありません。 $ cat .git/refs/heads/main bdcc6040408bacfb69727c0f2637bbcec1dbc487

Slide 98

Slide 98 text

98 ©MIXI refs について ~HEAD~ 最後に HEAD です。HEAD は先ほども⾔った通り、現在の commit を指す refs です。 .git/HEAD に保存されており、commit や checkout/switch などで書き変わります。ま た、branch 名で checkout/switch した時はコミットハッシュではなく branch の場所が 書き込まれるようになっています。

Slide 99

Slide 99 text

99 ©MIXI commit の仕組み(再掲) ここまでで、commit に関連する全てのオブジェクトと、仕組みを解説してきました。 commit の流れを再度まとめておきます。 ● コードを編集する ● 編集したコードをaddする ○ add したファイルの blob オブジェクトの⽣成 ○ index の更新 ● commitする ○ リポジトリ全体の tree オブジェクトの⽣成 ○ commit オブジェクトを⽣成 ○ HEAD の書き換え

Slide 100

Slide 100 text

©MIXI reset の仕組み

Slide 101

Slide 101 text

101 ©MIXI reset コマンド reset はオプション次第で⾊々なことが可能なサブコマンドです。 以下の⽤途で使ったことがあるかもしれません。 ● 作業の取り消し ● add の取り消し ● commit の取り消し reset についても実際の内部挙動を⾒ていきます。

Slide 102

Slide 102 text

102 ©MIXI reset コマンド reset では、基本的には以下の 3 つを書き換えることでそれらを実現しています。 ● ワークツリー(作業ディレクトリ) ● index ● HEAD おおまかには soft, mixed, hard の 3 種類のオプションがあり、指定した commit ハッ シュに向けて、それぞれの内容を書き換える。 
 HEAD
 index
 ワークツリー
 git reset --soft 書き換える
 
 
 git reset --mixed 書き換える
 書き換える
 
 git reset --hard 書き換える
 書き換える
 書き換える


Slide 103

Slide 103 text

103 ©MIXI reset コマンド どのオプションでも HEAD の書き換えはある。 なお、checkout/switch と異なり、reset では branch の参照先も書き換わる。 checkout/switch の場合 first commit
 master.txt を追加
 README.md に
 「master」と追記
 develop.txt を追加
 master
 README.md に
 「develop」と追記
 develop
 HEAD


Slide 104

Slide 104 text

104 ©MIXI reset コマンド どのオプションでも HEAD の書き換えはある。 なお、checkout/switch と異なり、reset では branch の参照先も書き換わる。 checkout/switch の場合 first commit
 master.txt を追加
 README.md に
 「master」と追記
 develop.txt を追加
 master
 README.md に
 「develop」と追記
 develop
 HEAD


Slide 105

Slide 105 text

105 ©MIXI reset コマンド どのオプションでも HEAD の書き換えはある。 なお、checkout/switch と異なり、reset では branch の参照先も書き換わる。 reset の場合 first commit
 master.txt を追加
 README.md に
 「master」と追記
 develop.txt を追加
 master
 README.md に
 「develop」と追記
 develop
 HEAD


Slide 106

Slide 106 text

106 ©MIXI reset コマンド どのオプションでも HEAD の書き換えはある。 なお、checkout/switch と異なり、reset では branch の参照先も書き換わる。 reset の場合 first commit
 master.txt を追加
 README.md に
 「master」と追記
 develop.txt を追加
 master
 README.md に
 「develop」と追記
 develop
 HEAD


Slide 107

Slide 107 text

107 ©MIXI reset コマンド ここまで解説した機能があることで、前述した⽤途を実現できます。 (再掲) ● commit の取り消し ○ 1 つ前の commit ハッシュに branch を向けることで、最新のコミットをなかっ たことにできる(branch の参照先を変えられる機能があるため) ● add の取り消し ○ git reset --mixed HEAD とすると、index を HEAD の状況に戻せるので、add を 取り消すことができる ● 作業の取り消し ○ git reset —hard HEAD とすると、ワークツリーの状況を HEAD に戻せる ○ ※現在では、restore の⽅が推奨

Slide 108

Slide 108 text

108 ©MIXI reset コマンド add, commitの取り消しについて補⾜ あくまで reset で⾏われているのは以下の操作です。 add や commit の内部動作で⾏なっていたことを完全に無かったことにできているでしょ うか? 
 HEAD
 index
 ワークツリー
 git reset --soft 書き換える
 
 
 git reset --mixed 書き換える
 書き換える
 
 git reset --hard 書き換える
 書き換える
 書き換える


Slide 109

Slide 109 text

109 ©MIXI add と commit の内部挙動 再掲 add した時に起こる内部挙動 ● blob オブジェクトの⽣成 ● index の更新 commit した時の内部挙動 ● index から tree オブジェクトを⽣成 ● commit オブジェクトを⽣成 ● HEAD を新しい commit ハッシュに書き換え

Slide 110

Slide 110 text

110 ©MIXI まとめ 以降はこの後の git challenge で取り組んでください。 ここまでの内容が分かっていれば、講義の最初に挙げた以下の問題が起きた時にも、 焦らず対処できるはずです。 ● ブランチをマージ前に間違えて消してしまった! ● コミットを誤って消してしまった! ● コミット前(ステージングエリア)のファイルを消してしまった!

Slide 111

Slide 111 text

©MIXI