Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
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