Share
Embed
Git 研修 Basic【MIXI 24新卒技術研修】
本スライドは、MIXIの2024年度新卒向け技術研修で使用された資料です。
<科目名>
Git 研修 Basic
<関連リンク>
動画▶ https://youtu.be/uRYg6Iw5sXs
※お願い※ 〜 資料・動画・リポジトリのご利用について〜
公開している資料や動画は、是非、勉強会や社内の研修などにご自由にお使いいただければと思いますが、以下のような場でのご利用はご遠慮ください。
- 受講者から参加費や授業料など金銭を集めるような場での利用
(会場費や飲食費など勉強会の運営に必要な実費を集める場合は問題ありません)
- 出典を削除または改変しての利用
MIXI ENGINEERS PRO
July 21, 2024
Video
Transcript
111 slides
-
22 ©MIXI 講師紹介 久⽥ 将成 ひさだ まさなり 2022年度新卒⼊社 ライブエクスペリエンス事業本部 ファンコミュニケーション部
Fansta開発グループ 業務: Ruby on Rails 、Next.js 、Flutter など 趣味: Rust など 好きなGitコマンド: git rebase 得意なこと: コンフリクトを起こすこと、夜更かし 苦⼿なこと: コンフリクトの解消、早起き -
33 ©MIXI 講師紹介 登内 雅⼈ とのうち まさと 2020 年度新卒⼊社 •
業務:開発本部 たんぽぽ室 たんぽぽグループ • ML系の研究開発やバックエンドを主に担当 • Python、Go、Flutter、Ruby • 趣味:格闘技、将棋、ポーカーとかにハマってる • 好きなGitコマンド:git push -f github pages: https://github.com/tonouchi510 -
4 ©MIXI タイムテーブル(予定) 10:30 - 12:00 Git研修 Basic (基礎 /
内部構造) 12:00 - 13:00 お昼休憩 13:00 - 16:30 Git Challenge 16:40 - 18:30 Git研修 Advanced(チーム開発について) -
5 ©MIXI ⽬次 1. Gitとは 2. Gitの基本的な使い⽅ 3. ブランチの使⽤ 4.
歴史の改変 5. その他便利機能 基礎編 1. Gitオブジェクト 2. コミットの仕組み 3. resetの仕組み 内部構造編 -
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 -
9 ©MIXI Gitとは 例えばファイル名を使ったバージョン管理 書類_最新.pdf 書類_修正版.pdf 書類_最終.pdf 書類_提出⽤.pdf 書類.pdf 書類(1).pdf
最新の版は? ひとつ前の版は? 複数⼈で扱うにはちょっと苦しい -
10 ©MIXI Gitとは Gitを使⽤したバージョン管理 書類.pdf 04/02 15:00 書類.pdf 04/03 10:00
書類.pdf 04/01 12:00 書類.pdf 04/02 13:00 最新版 初稿 差分が出せたり 好きな版に戻れたり この他にもチーム開発に便利な機能がたくさん! -
11 ©MIXI Gitとは 現代のソフトウェア開発における デファクトスタンダードが Git 今やバージョン管理に留まらず ⾃動化されたテストやビルド:CI ⾃動化されたデプロイ:CD の基盤としても使われている
Continuous Integration Continuous Delivery -
13 ©MIXI Gitの基本的な使い⽅ はじめにリポジトリ(repository)を作る Gitでバージョン管理したいディレクトリに移動してから $ git init 以下のように表⽰されたら成功! Initialized
empty Git repository in ディレクトリパス このディレクトリ内がGitが管理する範囲になり、これをリポジトリと呼ぶ ちなみに 既存のリポジトリで作業を始める場合はクローン(clone)する $ git clone リポジトリURL 参照: git-init Documentation git-clone Documentation もっとちなみに リポジトリ直下には .git というディレクトリが作られる 詳しくは内部構造編で! -
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 -
15 ©MIXI Gitの基本的な使い⽅ 変更をコミットするまでの段階はこんな感じ ワーキングディレクトリ ファイルを編集した状態 ステージングエリア ステージングされた状態 コミット コミットされた状態
$ git add $ git commit 各ファイルがどの段階にあるかを確認するには $ git status 参照: git-status Documentation -
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)も可 後述するブランチとかタグとか -
17 ©MIXI Gitの基本的な使い⽅ コミットをリモートリポジトリにプッシュ(push: アップロード)したり、 コミットをリモートリポジトリからプル(pull: ダウンロード)することで変更を共有する Push Pull Pull
Push コミットをプッシュする コミットをプルする $ git push $ git pull 参照: git-push Documentation git-pull Documentation -
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 -
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 <MIXIを追加> コミットをリバートする $ git revert コミットID 参照: git-revert Documentation -
20 ©MIXI Gitの基本的な使い⽅ タグ(tag)機能を使うと特定のコミットに⽬印を付けられる $ git tag タグ名 コミットID version1.2
version1.1 version1.0 リリースしたらバージョン名のタグを作る運⽤も多い印象 タグ名はコミットIDと同じように使える $ git switch タグ名 --detach $ git show タグ名 タグのついたコミットに移動するなら タグのついたコミットの詳細を⾒るなら 参照: git-tag Documentation -
23 ©MIXI main develop ブランチの使⽤ まずは develop という名前でブランチを作ってみる $ git
branch develop bca877d40 Commit 1 最初はmainやmasterという名前のブランチが作られている ブランチの⼀覧を確認してみる $ git branch * main develop 参照: git-branch Documentation -
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 -
25 ©MIXI ブランチの使⽤ コミットを追加してみる $ git commit 2a673e714 Commit 1
main f20100b9e Commit on develop develop -
26 ©MIXI ブランチの使⽤ コミットを追加してみる $ git commit 2a673e714 Commit 1
main f20100b9e Commit on develop develop 2f8ff17f6 Commit on main main 仮にmainにコミットが増えるとこうなる -
27 ©MIXI ブランチの使⽤ マージ先ブランチに移動する $ git checkout main 2a673e714 Commit
1 f20100b9e Commit on develop develop develop main 参照: git-merge Documentation 2f8ff17f6 Commit on main -
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 -
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 -
30 ©MIXI ブランチの使⽤ じゃあ、これは? 1 Hello, World! 2 1 Hello,
e-Mercury! 2 1 Hello, MIXI! 2 -
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: 競合)と呼ぶ コンフリクトが発⽣した場合は⼿動マージが必要 -
32 ©MIXI ブランチの使⽤ 直してみる 問題のファイルを開くとこうなっている 1 <<<<<<< HEAD 2 Hello,
e-Mercury! 3 4 ======= 5 Hello, MIXI! 6 >>>>>>> mixi コンフリクトーマーカー HEAD(今いるところ)の変更内容 ブランチ mixi の変更内容 これをあるべき姿に直してコミットすればよい -
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 していくのがおすすめ -
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 -
35 ©MIXI ブランチの使⽤ コンフリクトはできるだけ避けたくはあるものの、起こるときは起こる ⼿動マージは間違いやすいので注意して作業しよう それぞれのブランチで加えられた変更の意図を理解するのが近道 merge-base コマンドで分岐元が調べられる $ git
merge-base main develop 分岐元からの差分を⾒たり…… 含まれるコミットメッセージやPull requestを読んだり…… ⼤変だけど間違うともっと⼤変なので頑張ろう 参照: git-merge-base Documentation -
36 ©MIXI ブランチの使⽤ ところで fast-forward というマージがある この状態で develop を main
にマージすると…… 2a673e714 Commit 1 f20100b9e Commit on develop develop main develop $ git merge develop -
37 ©MIXI ブランチの使⽤ ところで fast-forward というマージがある この状態で develop を main
にマージすると…… こうなる 2a673e714 Commit 1 f20100b9e Commit on develop develop main develop $ git merge develop main -
38 ©MIXI main ブランチの使⽤ マージ対象ブランチの⽚⽅のみに変更がある場合、マージコミットは必須でない マージ先ブランチをマージ元ブランチの位置に移動することで 通常のマージと同じ結果を得られる これを fast-forward(早送り) と呼ぶ
2a673e714 Commit 1 f20100b9e Commit on develop develop main develop -
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 -
42 ©MIXI 歴史を改変してみる前にコミットログの構造を少し説明したい 歴史の改変 コミットは1つ前がどのコミットかを知っている(参照を持っている) bca877d40 最初のコミット 6aa4aa7ae 2番⽬のコミット 4e62a7326
3番⽬のコミット [HEAD] 新 古 つまり…… 参照 参照 新しいコミットから古いコミットは辿れる 古いコミットから新しいコミットは辿れない コミットの削除とはそのコミットが どこからも辿れなくなることを意味する ちなみに 加えて今いるところ(HEAD)や ブランチの先端のコミットを別途保存することで コミットログが描画できる -
43 ©MIXI 歴史の改変 最近のコミットをなかったことにするならリセット(reset) $ git reset コミットID よく使うオプションは以下 HEAD
HEAD 削除 --soft --mixed(デフォルト) --hard :変更はステージングされた状態で残す :変更はステージングされていない状態で残す :変更は破棄する 変更をステージングしたけどやっぱりやめたいときもresetを使う $ git reset . 参照: git-reset Documentation -
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 -
45 ©MIXI 歴史の改変 ブランチ上で作業していて分岐元のブランチが進んでしまった時は リベース(rebase)で追従するのが便利 歴史を改変するのが怖ければ代わりにマージしても同じ結果が得られるが リベースの⽅がコミットログはシンプルになる HEAD main $
git rebase --continue もしコンフリクトしたら解決後に continue で続⾏できる HEAD 参照: git-rebase Documentation $ git rebase main -
46 ©MIXI 歴史の改変 もっと⼤胆に歴史を変えるならリベースのインタラクティブモード 指定したコミットの次のコミット以降を対象にいろいろできる $ git rebase -i コミットID
HEAD このコミットを指定すると この範囲が対象になる -
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 -
48 ©MIXI 歴史の改変 他にもいろいろできるので⼀部抜粋して紹介 reword edit :コミットをそのまま残す :コミットメッセージを書き直す :コミットを編集する pick(デフォルト)
fixup exec squash :コミットを前のコミットとまとめる(前述) :squashっぽいけどメッセージはそのコミットのものを採⽤する :任意のコマンドを実⾏する ⾏を並べ替えるとコミットが並べ替えられたり…… ⾏を削除するとコミットが削除できたり…… 開いたエディタにできることが書いてあるので⼀度読んでみるとよい -
51 ©MIXI 歴史の改変 これをプッシュするには強制プッシュが必要 $ git push --force (-f) 削除
削除 もし他の⼈がコミットをプッシュしていたらそのコミットは消えてしまう -
53 ©MIXI 歴史の改変 多くの⼈で共有している⼤事なブランチは リモートリポジトリ側で強制プッシュを禁⽌する設定をしておくべき(ブランチ保護) とはいえ⾃分のブランチへの操作を誤ってひとりで悲しい思いをするのも切ないので ⽐較的安全な強制プッシュを覚えておこう --force-with-lease: リモートリポジトリ側のコミットログに知らない変更があればプッシュを中⽌する $
git push --force-with-lease --force-if-includes --force-if-includes: リモートリポジトリ側の最新のコミットに触った形跡がなければプッシュを中⽌する 超ざっくり解説 強制プッシュはいつもこれを使うくらいのつもりで問題ない 正確な説明は公式ドキュメントへ! https://git-scm.com/docs/git-push -
55 ©MIXI commit コマンドの --amend オプション 直前のコミットを上書きしてコミットする 他にも便利な機能があるので紹介しておく(その1) その他便利機能 submodule
参照: Git - Submodules リポジトリ内に別のリポジトリを内包できる cherry-pick 参照: git-cherry-pick Documentation 指定したコミットと同じ内容のコミットを今いるブランチに追加する stash 参照: git-stash Documentation コミットしていない変更を⼀時的に退避できる -(ハイフン) 1つ前にいたブランチを⽰す(例: $ git switch - で1つ前のブランチに戻る) -
57 ©MIXI add -A: すべての変更をステージする -p: 変更を部分的にステージする commit -a: すべての変更をステージしてからコミットする
-m ’メッセージ’: コミットメッセージをオプションで渡せる(エディタが開かない) -n: pre-commit, commit-msg hooks を無視する log --graph: コマンドライン上でグラフィカルに表⽰する --oneline: 1コミット1⾏で表⽰する --all: 今いるブランチ以外のコミットも表⽰する よく使うかもしれない細かいオプションとか(その1) その他便利機能 -
58 ©MIXI checkout -b ブランチ名: ブランチを作ってそこに移動する switch -c ブランチ名:ブランチを作ってそこに移動する merge
--abort: コンフリクトでマージが中断したときに、マージを中⽌する よく使うかもしれない細かいオプションとか(その2) その他便利機能 -
60 ©MIXI Git の内部構造を学ぶ意義 Git ⾃体は内部を知らなくとも⼗分使える優秀なツール • Git のサブコマンドが実際どういった挙動をしているのか •
内部構造がどうなっているか これらを知らなくとも⼗分使えるため、学んだことがある⼈は少ないかもしれない ⼀⽅で、仕組みや内部構造を知ることで以下のような利点がある • 毎回調べながら Git を使うという状況を脱せる • Git を使っていて何らかの問題が起きたときに⾃⼒で解決できる -
61 ©MIXI Git の内部構造を学ぶ意義 Git を使っていてこんな経験はないか? • ブランチをマージ前に間違えて消してしまった! • コミットを誤って消してしまった!
• コミット前(ステージングエリア)のファイルを消してしまった! 内部構造を学ぶことでこれらの問題に、⾃⼒で対処できるようになる。 -
62 ©MIXI Gitについての誤解 Git の内部構造を知る前だと、(僕も含め)各コマンドに対する印象は例えば以下のような イメージになるかもしれない。 1. commit とは、 ◦
add の操作を確定するもの? ◦ 親 commit との差分を保存しているもの? 2. branch とは、 ◦ 分岐した時点以降のコミットのこと? 3. reset とは、 ◦ add や commit を無かったことにできるコマンド? ◦ ファイルの変更を無かったことにできるコマンド? -
63 ©MIXI Gitについての誤解 => 全て間違い(厳密には) Git について、多くの⼈が誤解しているであろうポイントを紹介しました。 これらの実態が分かれば、誤った操作をしてしまった時に焦る必要がないことが分かるよ うになると思います。 ここからは、Git
がどのようにしてバージョン管理を実現しているかを理解するために、内 部構造を紐解いていきます。具体的には、.gitディレクトリの中⾝について取り扱っていき ます。 git init した時に できるあれ -
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について興味 ある⽅はこちら -
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 -
67 ©MIXI Git オブジェクト Git はバージョン管理に必要なデータを主に「オブジェクト」と呼ばれる概念で表現し、 `.git/objects`ディレクトリで管理しています。 オブジェクトは以下の4種類 • blob
オブジェクト ◦ ファイルの情報が⼊っているオブジェクト(バックアップ) • tree オブジェクト ◦ ディレクトリ情報が⼊っているオブジェクト • commit オブジェクト ◦ コミットの情報が⼊っているオブジェクト • tag オブジェクト ◦ annotated tag の情報が⼊っているオブジェクト ◦ 重要度が低いので省略 => 興味がある⼈はこちらを参照してください -
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 -
69 ©MIXI オブジェクトファイルの基本構成 • オブジェクトの種類:blob or tree or commit or
tag • オブジェクトのサイズ:数値(単位はbyte) • オブジェクトのコンテンツ:オブジェクトの種類によってさまざま 最初にオブジェクトの種類やサイズなどのメタデータが記録され、そのあとにコンテンツ が続きます。 これからオブジェクトの種類ごとに、順番に中⾝を⾒ていきます。 -
70 ©MIXI commit オブジェクト commit オブジェクトは、コミットの情報を記録するオブジェクトです。 実際に、Key=bdcc6040408bacfb69727c0f2637bbcec1dbc487 の commit オブジェク
トの中⾝を⾒てみます。 そのままだとファイルは zlib 圧縮されているので意味のない⽂字列が表⽰されます。 $ cat .git/objects/bd/cc6040408bacfb69727c0f2637bbcec1dbc487 x��M �0F]�� 2��_ADO"�db �)%�o7^����=>n�<umȞ�&�����G�5c�P=bvB� �`] �\r�A�i��kO�J2R�Z,�P�#�s�F,�J{ۦ 7������]}L���4�/��F���d�u��c��l�(E��#�4���� X�I�% -
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 <[email protected]> 1670215632 +0900 committer tonouchi510 <[email protected]> 1670215632 +0900 Add chapter_2.txt -
72 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key)
• 親 commit のハッシュ値 • committer と author のタイムスタンプ‧名前‧メールアドレス • コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 <[email protected]> 1670215632 +0900 committer tonouchi510 <[email protected]> 1670215632 +0900 Add chapter_2.txt 後ほど解説 -
73 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key)
• 親 commit のハッシュ値 • committer と author のタイムスタンプ‧名前‧メールアドレス • コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 <[email protected]> 1670215632 +0900 committer tonouchi510 <[email protected]> 1670215632 +0900 Add chapter_2.txt -
74 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key)
• 親 commit のハッシュ値 • committer と author のタイムスタンプ‧名前‧メールアドレス • コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 <[email protected]> 1670215632 +0900 committer tonouchi510 <[email protected]> 1670215632 +0900 Add chapter_2.txt -
75 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key)
• 親 commit のハッシュ値 • committer と author のタイムスタンプ‧名前‧メールアドレス • コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 <[email protected]> 1670215632 +0900 committer tonouchi510 <[email protected]> 1670215632 +0900 Add chapter_2.txt -
76 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key)
• 親 commit のハッシュ値 • committer と author のタイムスタンプ‧名前‧メールアドレス • コミットメッセージ $ git cat-file -p bdcc6040408bacfb69727c0f2637bbcec1dbc487 tree f9ccb461cbfb1837f611b5e31a070945b8cdb867 parent 63c833da2ed9fd43d3f000f35d2ee141ba42e411 author tonouchi510 <[email protected]> 1670215632 +0900 committer tonouchi510 <[email protected]> 1670215632 +0900 Add chapter_2.txt これをSHA-1ハッシュ化 したものがKeyになる -
77 ©MIXI commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key)
• 親 commit のハッシュ値 • committer と author のタイムスタンプ‧名前‧メールアドレス • コミットメッセージ これらのいずれか1つでも変わると、(SHA-1が衝突しない限り)別の commit ハッシュ になる。=> コミットは⼀意に定まる 親コミットのハッシュも含んでいるため、改ざんにも強い。 次に新出の これを解説 -
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 -
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 -
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 -
81 ©MIXI tree オブジェクト ルートディレクトリの tree オブジェクトから、順に辿ることでリポジトリの全てのblob オブジェクト(つまり、その時点のファイルの内容)にアクセスすることができます。 このように、Git はファイルシステム
になっているのです。 最後に blob オブジェクトについても ⾒ていきます。 -
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 差分が記録されて いるわけではない -
84 ©MIXI commit の仕組み ここまで紹介した 3つのオブジェクトに関する内容を踏まえて、コミットの仕組みを解説 していきます。 まずここまでの話を整理すると • commit
オブジェクトは、その時点のリポジトリのルートにあたる tree オブジェクト を参照 • tree オブジェクトは、その時点の ディレクトリ配下の tree オブジェクトと blob オブ ジェクトへの参照を持つ • blob オブジェクトは、その時点のファイルのフルバックアップ => commit オブジェクトを参照することで、そこから辿ることで commit 時点のリポジト リの状態を完全に再現できる => スナップショット -
85 ©MIXI 補⾜ Gitの checkout/switch で、かなり遠い履歴に移る際にも瞬時にリポジトリの状態を復元 できることに驚いた経験はないでしょうか? Gitがファイルを差分で管理しているとしたら、checkout/switch の⾼速な移動は実現で きません。コミットの実態がスナップショットになっていることが⾼速な
checkout/switch を可能にしています。 Gitではバージョン間を遷移する際にかかる時間は、履歴の遠さには依存せず、変更された ファイル数に依存します。 -
86 ©MIXI commit の流れ コミットには⼤きく3つの段階があります。 1. コードを編集する 2. 編集したコードをaddする 3.
commitする ステップ2で編集したコードを add しています。 この時、Git 内部で⾏われていることを深掘りしていきます。 -
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 -
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 -
89 ©MIXI add の内部挙動 add した時に起こる内部挙動は、基本的に以下の2点です。 • blob オブジェクトの⽣成 •
index の更新 実際に add してみていきます。 -
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 -
91 ©MIXI commit の内部挙動 次に、commit した時に起こる内部挙動は、以下の通りです。 • index から tree
オブジェクトを⽣成 • commit オブジェクトを⽣成 • HEAD を新しい commit ハッシュに書き換え それぞれ詳しく解説していきます。 -
92 ©MIXI commit の内部挙動 ~tree オブジェクトの作成~ tree オブジェクトの作成はこの段階で⾏われます。 commit すると、新たに作成されたディレクトリに対する
tree オブジェクトだけでなく、 リポジトリのルートディレクトリを含むすべてのディレクトリに対する tree オブジェクト の構築処理が動きます。 => index に記録された情報から構築可能 この時、効率化のために index に変更があった部分だけが新しい blob および tree オブ ジェクトに書き換えられ、それ以外の参照が変わらない部分はそのまま流⽤します。 -
93 ©MIXI commit の内部挙動 ~commit オブジェクトの作成~ 新しいルートディレクトリまでの tree オブジェクトが⽣成できたら、次は commit
オブ ジェクトを作成します。 commit オブジェクトに記録する情報(再掲) • リポジトリのルートディレクトリのtreeオブジェクトのハッシュ値(Key) • 親commitのハッシュ値 • committerとauthorのタイムスタンプ‧名前‧メールアドレス • コミットメッセージ 先述の通り、リポジトリのルートにあたるtreeオブジェクトを参照しているため、そこか らリポジトリ全体をたどることができます。 -
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 -
95 ©MIXI refs について refs は特定のコミットを指すポインタのようなものです。コミットハッシュのエイリアス とも⾔えます。具体的には以下のものが refs に該当します。 •
tag ◦ light-weight tag ◦ annotated tag(省略) • branch • HEAD(すでにcommitの仕組みで登場) -
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 -
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 -
98 ©MIXI refs について ~HEAD~ 最後に HEAD です。HEAD は先ほども⾔った通り、現在の commit
を指す refs です。 .git/HEAD に保存されており、commit や checkout/switch などで書き変わります。ま た、branch 名で checkout/switch した時はコミットハッシュではなく branch の場所が 書き込まれるようになっています。 -
99 ©MIXI commit の仕組み(再掲) ここまでで、commit に関連する全てのオブジェクトと、仕組みを解説してきました。 commit の流れを再度まとめておきます。 • コードを編集する
• 編集したコードをaddする ◦ add したファイルの blob オブジェクトの⽣成 ◦ index の更新 • commitする ◦ リポジトリ全体の tree オブジェクトの⽣成 ◦ commit オブジェクトを⽣成 ◦ HEAD の書き換え -
101 ©MIXI reset コマンド reset はオプション次第で⾊々なことが可能なサブコマンドです。 以下の⽤途で使ったことがあるかもしれません。 • 作業の取り消し •
add の取り消し • commit の取り消し reset についても実際の内部挙動を⾒ていきます。 -
102 ©MIXI reset コマンド reset では、基本的には以下の 3 つを書き換えることでそれらを実現しています。 • ワークツリー(作業ディレクトリ)
• index • HEAD おおまかには soft, mixed, hard の 3 種類のオプションがあり、指定した commit ハッ シュに向けて、それぞれの内容を書き換える。 HEAD index ワークツリー git reset --soft <commit ハッシュ> 書き換える git reset --mixed <commit ハッシュ> 書き換える 書き換える git reset --hard <commit ハッシュ> 書き換える 書き換える 書き換える -
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 -
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 -
105 ©MIXI reset コマンド どのオプションでも HEAD の書き換えはある。 なお、checkout/switch と異なり、reset では
branch の参照先も書き換わる。 reset の場合 first commit master.txt を追加 README.md に 「master」と追記 develop.txt を追加 master README.md に 「develop」と追記 develop HEAD -
106 ©MIXI reset コマンド どのオプションでも HEAD の書き換えはある。 なお、checkout/switch と異なり、reset では
branch の参照先も書き換わる。 reset の場合 first commit master.txt を追加 README.md に 「master」と追記 develop.txt を追加 master README.md に 「develop」と追記 develop HEAD -
107 ©MIXI reset コマンド ここまで解説した機能があることで、前述した⽤途を実現できます。 (再掲) • commit の取り消し ◦
1 つ前の commit ハッシュに branch を向けることで、最新のコミットをなかっ たことにできる(branch の参照先を変えられる機能があるため) • add の取り消し ◦ git reset --mixed HEAD とすると、index を HEAD の状況に戻せるので、add を 取り消すことができる • 作業の取り消し ◦ git reset —hard HEAD とすると、ワークツリーの状況を HEAD に戻せる ◦ ※現在では、restore の⽅が推奨 -
108 ©MIXI reset コマンド add, commitの取り消しについて補⾜ あくまで reset で⾏われているのは以下の操作です。 add
や commit の内部動作で⾏なっていたことを完全に無かったことにできているでしょ うか? HEAD index ワークツリー git reset --soft <commit ハッシュ> 書き換える git reset --mixed <commit ハッシュ> 書き換える 書き換える git reset --hard <commit ハッシュ> 書き換える 書き換える 書き換える -
109 ©MIXI add と commit の内部挙動 再掲 add した時に起こる内部挙動 •
blob オブジェクトの⽣成 • index の更新 commit した時の内部挙動 • index から tree オブジェクトを⽣成 • commit オブジェクトを⽣成 • HEAD を新しい commit ハッシュに書き換え -
110 ©MIXI まとめ 以降はこの後の git challenge で取り組んでください。 ここまでの内容が分かっていれば、講義の最初に挙げた以下の問題が起きた時にも、 焦らず対処できるはずです。 •
ブランチをマージ前に間違えて消してしまった! • コミットを誤って消してしまった! • コミット前(ステージングエリア)のファイルを消してしまった!