Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Git 研修【MIXI 26新卒技術研修】

Git 研修【MIXI 26新卒技術研修】

本スライドは、MIXIの2026年度新卒向け技術研修で使用された資料です。
 
MIXI 2026新卒技術研修
『Git 研修』
 
───────────────────────────────
※皆様へのお願い※ 資料・動画・リポジトリのご利用について
───────────────────────────────
公開している資料や動画は、是非、勉強会や社内の研修などにご自由にお使いいただければと思いますが、以下のような場でのご利用はご遠慮ください。
- 受講者から参加費や授業料など金銭を集めるような場での利用
(会場費や飲食費など勉強会の運営に必要な実費を集める場合は問題ありません)
- 出典を削除または改変しての利用

Avatar for MIXI ENGINEERS

MIXI ENGINEERS PRO

July 22, 2026

More Decks by MIXI ENGINEERS

Other Decks in Technology

Transcript

  1. 講師紹介 櫛引 淳之介 くしびき じゅんのすけ 2025年度新卒⼊社 開発本部 たんぽぽ室 モンストグループ 業務:

    モンストのインフラ / Terraform、AWS、Go など 趣味: ⾳楽ライブ鑑賞、⽇記 得意なこと: 家に引きこもること 苦⼿なこと: ⾞の運転 好きなGitコマンド: git ©MIXI reset --hard 33
  2. ⽬次 基礎編 1. Gitとは 2. Gitの基本的な使い⽅ 3. ブランチの使⽤ 4. 歴史の改変

    5. その他便利機能 ©MIXI 内部構造編 1. Gitオブジェクト 2. コミットの仕組み 3. resetの仕組み 4
  3. Gitとは Gitを使⽤したバージョン管理 書類.pdf 04/01 12:00 初稿 書類.pdf 04/02 13:00 差分が出せたり

    最新版 書類.pdf 04/02 15:00 書類.pdf 04/03 10:00 好きな版に戻れたり この他にもチーム開発に便利な機能がたくさん! ©MIXI 9
  4. Gitの基本的な使い⽅ はじめにリポジトリ(repository)を作る Gitでバージョン管理したいディレクトリに移動してから $ git init 以下のように表⽰されたら成功! Initialized empty Git

    repository in ディレクトリパス このディレクトリ内がGitが管理する範囲になり、これをリポジトリと呼ぶ ちなみに もっとちなみに ©MIXI 既存のリポジトリで作業を始める場合はクローン(clone)する $ git clone リポジトリURL リポジトリ直下には .git というディレクトリが作られる 詳しくは内部構造編で! 参照: git-init Documentation git-clone Documentation 12
  5. Gitの基本的な使い⽅ Gitでは「コミット(commit)」という単位で変更を保存する コミット コミット コミット コミット 書類.pdf 04/01 12:00 書類.pdf

    04/02 13:00 書類.pdf 04/02 15:00 書類.pdf 04/03 10:00 全部なら -A オプション 変更をコミット対象にする(ステージング) $ git add ファイル名 ステージングした変更でコミットする ©MIXI 参照: git-add Documentation git-commit Documentation $ git commit 13
  6. Gitの基本的な使い⽅ 変更をコミットするまでの段階はこんな感じ ファイルを編集した状態 ワーキングディレクトリ $ git add ステージングされた状態 ステージングエリア $

    git commit コミットされた状態 各ファイルがどの段階にあるかを確認するには ©MIXI 参照: git-status Documentation コミット $ git status 14
  7. Gitの基本的な使い⽅ コミットログを⾒てみる コミット ID コミットメッセージ 4e62a7326 3番⽬のコミット [HEAD] $ git

    log --oneline --graph コミットIDはコミットを⼀意に識別するID コマンド内でコミットを指定する場合に使ったりする 例えばコミットの詳細を⾒るには 6aa4aa7ae 2番⽬のコミット $ git show コミットID 他にもコミット間の差分を⾒るには $ git diff コミットID1 コミットID2 bca877d40 最初のコミット ©MIXI ちなみに 最後に ^ をつけるとその1つ前のコミット、 HEAD を指定すると今いるコミットを⽰す もっとちなみに コミットID部分は正確には参照(refs)も可 後述するブランチとかタグとか 参照: git-log Documentation git-show Documentation git-diff Documentation 15
  8. Gitの基本的な使い⽅ 別のコミットに戻りたいときはチェックアウト(checkout) $ git checkout コミットID もしくは $ git switch

    コミットID --detach ファイルを別のコミット時点に戻したいときもチェックアウト $ git checkout コミット ID ファイル名 もしくは $ git restore ファイル名 -s コミットID ©MIXI 参照: git-checkout Documentation git-switch Documentation Git - git-restore Documentation 17
  9. Gitの基本的な使い⽅ コミットを打ち消したいときはリバート(revert) 指定したコミットと逆のコミットを追加する 1 Hello, World! 2 MIXIを追加 Revert <MIXIを追加>

    1 Hello, World! 2 Hello, MIXI! 3 1 Hello, World! 2 Hello, MIXI! 3 revert コミットをリバートする ©MIXI 参照: git-revert Documentation $ git revert コミットID 18
  10. Gitの基本的な使い⽅ タグ(tag)機能を使うと特定のコミットに⽬印を付けられる $ git tag タグ名 コミットID リリースしたらバージョン名のタグを作る運⽤も多い印象 version1.0 version1.1

    version1.2 タグ名はコミットIDと同じように使える タグのついたコミットに移動するなら $ git switch タグ名 --detach タグのついたコミットの詳細を⾒るなら $ git show タグ名 ©MIXI 参照: git-tag Documentation 19
  11. ブランチの使⽤ まずは develop という名前でブランチを作ってみる $ git branch develop ブランチの⼀覧を確認してみる $

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

    git branch * main develop $ git checkout develop develop ブランチに移動してみる または $ git switch develop $ git branch 今いるブランチを確認してみる 最初はmainやmasterという名前のブランチが作られている bca877d40 Commit 1 ©MIXI 参照: git-branch Documentation main main * develop develop 23
  13. ブランチの使⽤ $ git checkout main マージ先ブランチに移動する 2f8ff17f6 Commit on main

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

    develop マージコミット 95e9ea33b Merge branch ‘develop’ f20100b9e Commit on develop main develop 2a673e714 Commit 1 ©MIXI 参照: git-merge Documentation 27
  15. ブランチの使⽤ マージの際、両ブランチの変更内容は⾃動でいい感じに混ぜられる 1 Hello, World! 2 and 3 Hello, MIXI!

    4 1 Hi, World! 2 and 3 Hello, MIXI! 4 1 Hi, World! 2 and 3 Yeah, MIXI! 4 1 Hello, World! 2 and 3 Yeah, MIXI! 4 ©MIXI 28
  16. ブランチの使⽤ マージしてみると怒られる Auto-merging hello.txt CONFLICT (content): Merge conflict in hello.txt

    Automatic merge failed; fix conflicts and then commit the result. (以下意訳) hello.txt のマージでコンフリクトが起きたよ。 ⾃動マージが失敗しちゃったからコンフリクトを直してからコミットしてね。 このように⾃動マージに失敗した状況をコンフリクト(conflict: 競合)と呼ぶ コンフリクトが発⽣した場合は⼿動マージが必要 ©MIXI 30
  17. ブランチの使⽤ 直してみる 問題のファイルを開くとこうなっている コンフリクトーマーカー 1 <<<<<<< HEAD 2 Hello, e-Mercury!

    3 4 ======= 5 Hello, MIXI! 6 >>>>>>> mixi HEAD(今いるところ)の変更内容 ブランチ mixi の変更内容 これをあるべき姿に直してコミットすればよい ©MIXI 31
  18. ブランチの使⽤ 例えば Hello, MIXI! を残すならこうする もしくは両⽅残すならこうする 忘れずに add してコミットすれば⼿動マージ完了! 1

    Hello, MIXI! 2 1 Hello, e-Mercury! 2 Hello, MIXI! 3 $ git add hello.txt $ git commit ちなみに ©MIXI $ git status でコンフリクトしているファイルの⼀覧が確認できる たくさんある場合は直したファイルから add していくのがおすすめ 32
  19. ブランチの使⽤ マージは⾏ごとに処理されるのでこの場合もコンフリクトが起きる 1 Hi, World! 2 1 Hello, World! 2

    1 Hello, MIXI! 2 1 <<<<<<< HEAD 2 Hi, World! 3 4 ======= 5 Hello, MIXI! 6 >>>>>>> mixi ©MIXI 1 Hi, MIXI! 2 33
  20. ブランチの使⽤ コンフリクトはできるだけ避けたくはあるものの、起こるときは起こる ⼿動マージは間違いやすいので注意して作業しよう それぞれのブランチで加えられた変更の意図を理解するのが近道 merge-base コマンドで分岐元が調べられる $ git merge-base main

    develop 分岐元からの差分を⾒たり…… 含まれるコミットメッセージやPull requestを読んだり…… ⼤変だけど間違うともっと⼤変なので頑張ろう ©MIXI 参照: git-merge-base Documentation 34
  21. ブランチの使⽤ ところで fast-forward というマージがある この状態で develop を main にマージすると…… $

    git merge develop こうなる f20100b9e Commit on develop 2a673e714 Commit 1 ©MIXI develop main main 36
  22. ブランチの使⽤ デフォルトだと可能な限りfast-forwardするようになっている fast-forward しないようにするなら 逆にfast-forwardを強制するなら $ git merge develop --no-ff

    $ git merge develop --ff-only fast-forwardマージはコミットログがシンプルになる⼀⽅、マージした形跡が残らない 作りたいコミットログやチームの⽂化によって使い分けられるようになろう f20100b9e Commit on develop 2a673e714 Commit 1 ©MIXI develop main main 38
  23. コミットの退避 ワークスペースやステージングエリアに変更がある状態ではブランチ移動ができない ⼀旦他ブランチで作業して戻ってきたいときは stash が便利 変更を退避 $ git stash 退避された変更の⼀覧

    $ git stash list 変更を復元 $ git stash apply stash番号 退避された変更を削除 $ git stash drop stash番号 $ git stash pop を使うとコマンド1つで最新の変更を復元&削除できて便利! ©MIXI 参照: git-stash Documentation 39
  24. 歴史の改変 歴史を改変してみる前にコミットログの構造を少し説明したい コミットは1つ前がどのコミットかを知っている(参照を持っている) 新 4e62a7326 3番⽬のコミット [HEAD] つまり…… 新しいコミットから古いコミットは辿れる 古いコミットから新しいコミットは辿れない

    参照 6aa4aa7ae 2番⽬のコミット ちなみに 加えて今いるところ(HEAD)や ブランチの先端のコミットを別途保存することで コミットログが描画できる 参照 bca877d40 最初のコミット コミットの削除とはそのコミットが どこからも辿れなくなることを意味する 古 ©MIXI 42
  25. 歴史の改変 最近のコミットをなかったことにするならリセット(reset) HEAD $ git reset コミットID HEAD 削除 よく使うオプションは以下

    --soft :変更はステージングされた状態で残す --mixed(デフォルト):変更はステージングされていない状態で残す :変更は破棄する --hard 変更をステージングしたけどやっぱりやめたいときもresetを使う ©MIXI 参照: git-reset Documentation $ git reset . 43
  26. 歴史の改変 $ git reflog 操作を間違えたら reflog で復旧できる……かも 以下はresetで最新のコミットを2つ消し⾶ばした時の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 する前にいたコミット 561f0de に再び reset することでもとに戻せる $ git reset 561f0de ©MIXI 参照: git-reflog Documentation 44
  27. 歴史の改変 ブランチ上で作業していて分岐元のブランチが進んでしまった時は リベース(rebase)で追従するのが便利 $ git rebase main main HEAD HEAD

    歴史を改変するのが怖ければ代わりにマージしても同じ結果が得られるが リベースの⽅がコミットログはシンプルになる もしコンフリクトしたら解決後に continue で続⾏できる $ git rebase --continue ©MIXI 参照: git-rebase Documentation 45
  28. 歴史の改変 よく使うのはコミットをまとめる squash 前のコミットに吸収される k1 or w k2 or w

    pick 56da94f work1 pick 4a1d066 work2 pick f908cb9 work3 k3 or w pick 56da94f work1 squash 4a1d066 work2 squash f908cb9 work3 ,3 2 , k1 r o w ©MIXI 47
  29. 歴史の改変 他にもいろいろできるので⼀部抜粋して紹介 pick(デフォルト):コミットをそのまま残す reword :コミットメッセージを書き直す edit :コミットを編集する squash :コミットを前のコミットとまとめる(前述) fixup

    :squashっぽいけどメッセージはそのコミットのものを採⽤する exec :任意のコマンドを実⾏する ⾏を並べ替えるとコミットが並べ替えられたり…… ⾏を削除するとコミットが削除できたり…… 開いたエディタにできることが書いてあるので⼀度読んでみるとよい ©MIXI 48
  30. 歴史の改変 多くの⼈で共有している⼤事なブランチは リモートリポジトリ側で強制プッシュを禁⽌する設定をしておくべき(ブランチ保護) とはいえ⾃分のブランチへの操作を誤ってひとりで悲しい思いをするのも切ないので ⽐較的安全な強制プッシュを覚えておこう $ git push --force-with-lease --force-if-includes

    強制プッシュはいつもこれを使うくらいのつもりで問題ない --force-with-lease: リモートリポジトリ側のコミットログに知らない変更があればプッシュを中⽌する 超ざっくり解説 --force-if-includes: リモートリポジトリ側の最新のコミットに触った形跡がなければプッシュを中⽌する 正確な説明は公式ドキュメントへ! https://git-scm.com/docs/git-push ©MIXI 53
  31. その他便利機能 他にも便利な機能があるので紹介しておく commit コマンドの --amend オプション 直前のコミットを上書きしてコミットする submodule 参照: Git

    - Submodules リポジトリ内に別のリポジトリを内包できる cherry-pick 参照: git-cherry-pick Documentation 指定したコミットと同じ内容のコミットを今いるブランチに追加する -(ハイフン) 1つ前にいたブランチを⽰す(例: $ git switch - で1つ前のブランチに戻る) hooks 参照: Git Hooks 指定した操作の前や後に任意の処理を実⾏したりできる ©MIXI 55
  32. その他便利機能 よく使うかもしれない細かいオプションとか(その1) add -A: すべての変更をステージする -p: 変更を部分的にステージする commit -a: すべての変更をステージしてからコミットする

    -m ’メッセージ’: コミットメッセージをオプションで渡せる(エディタが開かない) -n: pre-commit, commit-msg hooks を無視する log --graph: コマンドライン上でグラフィカルに表⽰する --oneline: 1コミット1⾏で表⽰する --all: 今いるブランチ以外のコミットも表⽰する ©MIXI 57
  33. 講師紹介 森⼭ 堅樹 もりやま けんじゅ 2022 年度新卒⼊社 ©MIXI • •

    本:デザイン本部テクニカルデザイン室 • • 趣味:ゲーム Steamで300くらい持ってます 兼:開発本部 たんぽぽ室 映像開発グループ • ARを⽤いた映像合成、その他R &D • C++ Python TypeScript Shader UE5 好きなGitコマンド:git reflog 61 61
  34. Gitの内部構造を知るメリット 1 トラブルにあった際、⾼い精度で情報検索ができる ◦ ◦ 2 Gitの強み/弱みを深く知れる ◦ ◦ 3

    Gitでやらない⽅がいいことって? 他のVCSとどこを⽐べればいいの? 他のVCSに⾏った時に、周辺知識によって理解がしやすくなる ◦ ◦ ©MIXI エラーが起きた原因、妥当性の考察 出てきた解決策に対しての評価 Gitでは〇〇だったけど、こっちは△△なんだな この部分はGitと似ているんだな… 66
  35. Gitについての誤解 Git の内部構造を知る前だと、(僕も含め)各コマンドに対する印象は例えば以下のような イメージになるかもしれない。 1. commit とは、 ◦ add の操作を確定するもの?

    ◦ 2. branch とは、 ◦ 3. 作業を分けるだけのもの? reset とは、 ◦ ◦ ©MIXI 親 commit との差分を保存しているもの? add や commit を無かったことにできるコマンド? ファイルの変更を無かったことにできるコマンド? 67
  36. .git ディレクトリ ⼿元の適当な .gitディレクトリ の中を眺めてみてください もしなければ以下のリポジトリをクローンして使ってください => 2026BeginnerTrainingGit $ git

    clone [email protected]:mixigroup/2026BeginnerTrainingGit.git $ ls .git/objects info pack 最初はPackfileに圧縮 されてしまっている Packfileについて興味 ある⽅はこちら # packfileを解凍する $ mkdir temp && cd temp $ git init $ git unpack-objects < ../2026BeginnerTrainingGit/.git/objects/pack/pack-xxx.pack $ find .git/objects -not -name 'pack' -a -not -name 'info' -type d -mindepth 1 | xargs -I {} mv {} ../2026BeginnerTrainingGit/.git/objects/ $ cd ../2026BeginnerTrainingGit ©MIXI 69
  37. .git ディレクトリ とりあえず ls して中⾝を⾒てみる $ ls .git COMMIT_EDITMSG HEAD

    config objects packed-refs refs Example description hooks index info logs まずは objects ディレクトリを⾒ていく $ ls .git/objects 18 2a 3a 94 20 2b 44 a5 Example ab c2 c7 d4 da df info pack $ ls .git/objects/2c/ 108c00a5b976158a0b5ccff04b8261bfe3d7db 中にさらにサブディレクトリがあり、その中にファイルがある => Gitオブジェクト ©MIXI 70
  38. Git オブジェクト Git はバージョン管理に必要なデータを主に「オブジェクト」と呼び、 .git/objectsディレクトリで管理しています。 オブジェクトは以下の4種類 • blob オブジェクト ◦

    • tree オブジェクト ◦ • コミットの情報が⼊っているオブジェクト tag オブジェクト ◦ ◦ ©MIXI ディレクトリ情報が⼊っているオブジェクト commit オブジェクト ◦ • ファイルの中⾝が⼊っているオブジェクト(バックアップ) annotated tag の情報が⼊っているオブジェクト 重要度が低いので省略 => 興味がある⼈はこちらを参照してください 72
  39. Git オブジェクト Git はこれらのオブジェクトを Key-Value Store として管理している。 1. 2. 3.

    それぞれのオブジェクト(Value)を作成 オブジェクトの中⾝を SHA-1 ハッシュ化した値をKeyとする オブジェクトを zlib 圧縮した上で、.git/objects/以下に Key をファイル名として保存 ◦ 検索効率性のために、Key の先頭2⽂字でサブディレクトリを切る $ ls .git/objects 18 2a 3a 94 20 2b 44 a5 Example ab c2 c7 d4 da df info pack $ ls .git/objects/ab/ f5c28c73d56830e3e7cc0722be63d4d32b51a4 ※SHA-1:https://ja.wikipedia.org/wiki/SHA-1 ※Zlib:https://ja.wikipedia.org/wiki/Zlib ©MIXI 73
  40. オブジェクトファイルの基本構成 • • • オブジェクトの種類:blob or tree or commit or

    tag オブジェクトのサイズ:数値(単位はbyte) オブジェクトのコンテンツ:オブジェクトの種類によってさまざま 最初にオブジェクトの種類やサイズなどのメタデータが記録され、そのあとにコンテンツ が続きます。 これからオブジェクトの種類ごとに、順番に中⾝を⾒ていきます。 ©MIXI 74
  41. commit オブジェクト commit オブジェクトは、コミットの情報を記録するオブジェクトです。 実際に、Key=abf5c28c73d56830e3e7cc0722be63d4d32b51a4 の commit オブジェク トの中⾝を⾒てみます。 Example

    $ cat .git/objects/ab/f5c28c73d56830e3e7cc0722be63d4d32b51a4 �a��,jQvt�˶Û���l��ID\Ĕt�5��Y��W/���‫ۼ‬ǗmY�!LJ��A� �u`_��S, �Y��ACN�bcw���)y�2�2�<ri ���q��$�4���|I ��#VD'?��Cu/���=���ɶ*�i���o��?�� RS% ���&ˡp�i‫����ڞ‬Y��u�)?U�15g��; �W�:���{��ï�/5�:�P�% そのままだとファイルは zlib 圧縮されているので意味のない⽂字列が表⽰されます。 ©MIXI 76
  42. commit オブジェクト Git オブジェクトの内容を⾒たい場合は、cat-file というサブコマンドを使⽤します。 # tオプションはオブジェクトの種類 $ git cat-file

    -t abf5c28c73d56830e3e7cc0722be63d4d32b51a4 commit # sオプションはオブジェクトのサイズ $ git cat-file -s abf5c28c73d56830e3e7cc0722be63d4d32b51a4 253 配管コマンド 低レイヤー向けの操作 磁器コマンド 普段打つような操作 # pオプションはオブジェクトの中⾝ $ git cat-file -p abf5c28c73d56830e3e7cc0722be63d4d32b51a4 tree 3a2ccd96b192df80437a06ae7ca9bd2d254ef3fb parent 44108c00a5b976158a0b5ccff04b8261bfe3d7db author kenju.moriyama <qujen-caballus> 1744032231 +0900 committer kenju.moriyama <qujen-caballus> 1744032231 +0900 [add]add the second file second-commit.txt 参考 Gitの内側 - 配管(Plumbing)と磁器(Porcelain) ©MIXI 77
  43. commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • • • • 後ほど解説 リポジトリのルートディレクトリの

    tree オブジェクトのハッシュ値(Key) 親 commit のハッシュ値 committer と author のタイムスタンプ‧名前‧メールアドレス コミットメッセージ $ git cat-file -p abf5c28c73d56830e3e7cc0722be63d4d32b51a4 tree 3a2ccd96b192df80437a06ae7ca9bd2d254ef3fb parent 44108c00a5b976158a0b5ccff04b8261bfe3d7db author kenju.moriyama <qujen-caballus> 1744032231 +0900 committer kenju.moriyama <qujen-caballus> 1744032231 +0900 Example [add]add the second file second-commit.txt ©MIXI 78
  44. commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • • • • リポジトリのルートディレクトリの tree

    オブジェクトのハッシュ値(Key) 親 commit のハッシュ値 committer と author のタイムスタンプ‧名前‧メールアドレス コミットメッセージ $ git cat-file -p abf5c28c73d56830e3e7cc0722be63d4d32b51a4 tree 3a2ccd96b192df80437a06ae7ca9bd2d254ef3fb parent 44108c00a5b976158a0b5ccff04b8261bfe3d7db author kenju.moriyama <qujen-caballus> 1744032231 +0900 committer kenju.moriyama <qujen-caballus> 1744032231 +0900 Example [add]add the second file second-commit.txt ©MIXI 79
  45. commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • • • • リポジトリのルートディレクトリの tree

    オブジェクトのハッシュ値(Key) 親 commit のハッシュ値 committer と author のタイムスタンプ‧名前‧メールアドレス(アカウント名) コミットメッセージ $ git cat-file -p abf5c28c73d56830e3e7cc0722be63d4d32b51a4 tree 3a2ccd96b192df80437a06ae7ca9bd2d254ef3fb parent 44108c00a5b976158a0b5ccff04b8261bfe3d7db author kenju.moriyama <qujen-caballus> 1744032231 +0900 committer kenju.moriyama <qujen-caballus> 1744032231 +0900 Example [add]add the second file second-commit.txt ©MIXI 80
  46. commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • • • • リポジトリのルートディレクトリの tree

    オブジェクトのハッシュ値(Key) 親 commit のハッシュ値 committer と author のタイムスタンプ‧名前‧メールアドレス コミットメッセージ $ git cat-file -p abf5c28c73d56830e3e7cc0722be63d4d32b51a4 tree 3a2ccd96b192df80437a06ae7ca9bd2d254ef3fb parent 44108c00a5b976158a0b5ccff04b8261bfe3d7db author kenju.moriyama <qujen-caballus> 1744032231 +0900 committer kenju.moriyama <qujen-caballus> 1744032231 +0900 Example [add]add the second file second-commit.txt ©MIXI 81
  47. commit オブジェクト commit オブジェクトに含まれている情報は以下の通り。 • • • • 次に新出の これを解説

    リポジトリのルートディレクトリの tree オブジェクトのハッシュ値(Key) 親 commit のハッシュ値 committer と author のタイムスタンプ‧名前‧メールアドレス コミットメッセージ これらのいずれか1つでも変わると、(SHA-1が衝突しない限り)別の commit ハッシュ になる。=> コミットは⼀意に定まる 親コミットのハッシュも含んでいるため、改ざんにも強い。 ©MIXI 82
  48. blob オブジェクト blobオブジェクトは、ファイルの実際のバックアップに当たるオブジェクトで、ある時点 (バージョン)でのファイルの情報を記録しています。 $ git rev-list --objects --all 20226ccdeaac3afd6030b6c47565aeb2edf88d9d

    abf5c28c73d56830e3e7cc0722be63d4d32b51a4 44108c00a5b976158a0b5ccff04b8261bfe3d7db c75f1ee6651b241f911e51368998f7c3b3b9ca17 2a1f5aec5669ca3126585393e586c6f7381c0074 182366232745d29b616008e23d5ac365f51df489 README.md 2bceb6cc10ab98b13ef6b3624bc464d5c020eb57 git-internals da0d74633ad2023909aea38ce45fcaf1b2fa0e2f git-internals/first-commit.txt c2f0160862bf1fbc7f338d3a395d9880f5ef7881 git-internals/second-commit.txt 3a2ccd96b192df80437a06ae7ca9bd2d254ef3fb d46017d015af8702f85a62a2eeeb62ca33629e13 README.md 943f712e856b69d55c3422f81f4e979416aa5fea df951d06764371c920ebb2e1b3658fc473042446 git-internals a51f746068d56a49d5bd788f0f042bf100bf1a96 ©MIXI Example 84
  49. blob オブジェクト blobオブジェクトは、ファイルの実際のバックアップに当たるオブジェクトで、ある時点 (バージョン)でのファイルの情報を記録しています。 $ git cat-file -p d46017d015af8702f85a62a2eeeb62ca33629e13 Example

    # 2025BeginnerTrainingGit 株式会社MIXI 新卒向けGit研修リポジトリ $ git cat-file -p 182366232745d29b616008e23d5ac365f51df489 # 2025BeginnerTrainingGit 株式会社MIXI 新卒向けGit研修リポジトリ Gitの内部構造の説明に使⽤します。 本リポジトリをcloneした後に、以下のコマンドを実⾏して.... 差分が記録されて いるわけではない この2つはどちらも同⼀ファイル(README.md)の blob オブジェクトで、それぞれ特定 のバージョンに対応する blob オブジェクトとなっています。 ここで重要なのは、blob オブジェクトは 「ファイルの差分ではなく、ある時点でのファイルの中⾝そのものを記録している」 ということです。 => Gitの機能を語る上で重要な要素 ©MIXI 85
  50. tree オブジェクト treeオブジェクトはディレクトリとしての情報を保持しています。バージョンごとに、Git 管理下の全てのディレクトリに対応する tree オブジェクトが作成されます。 実際に、tree のオブジェクトの中⾝をみていきます。 $ git

    cat-file -t 2bceb6cc10ab98b13ef6b3624bc464d5c020eb57 tree Example $ git cat-file -s 2bceb6cc10ab98b13ef6b3624bc464d5c020eb57 89 $ git cat-file -p 2bceb6cc10ab98b13ef6b3624bc464d5c020eb57 100644 blob da0d74633ad2023909aea38ce45fcaf1b2fa0e2f first-commit.txt 100644 blob c2f0160862bf1fbc7f338d3a395d9880f5ef7881 second-commit.txt ©MIXI 87
  51. tree オブジェクト $ git cat-file -p 2bceb6cc10ab98b13ef6b3624bc464d5c020eb57 100644 blob da0d74633ad2023909aea38ce45fcaf1b2fa0e2f

    first-commit.txt 100644 blob c2f0160862bf1fbc7f338d3a395d9880f5ef7881 second-commit.txt Example こちらは git-internals ディレクトリのある時点の tree オブジェクトです。左から順に、 パーミッション、種類、Key、ファイル名が記録されています。 => この tree オブジェクトが作られた時点での、「そのディレクトリに存在したファイ ル」と、「そのバージョンの blobハッシュ値(Key)」 ※(再)blob オブジェクトはファイルの情報が⼊っているオブジェクト ©MIXI 88
  52. tree オブジェクト 次に、同じバージョンでの、リポジトリのルートディレクトリに対応するtreeオブジェク トも⾒ていきます。 $ git cat-file -p abf5c28c73d56830e3e7cc0722be63d4d32b51a4 tree

    3a2ccd96b192df80437a06ae7ca9bd2d254ef3fb … Example git cat-file -p 3a2ccd96b192df80437a06ae7ca9bd2d254ef3fb 100644 blob d46017d015af8702f85a62a2eeeb62ca33629e13 README.md 040000 tree 2bceb6cc10ab98b13ef6b3624bc464d5c020eb57 git-internals ルートディレクトリにあるファイルの他に、先ほどの git-internals ディレクトリに関する treeオブジェクトへの参照(Key=2bceb6cc10ab98b13ef6b3624bc464d5c020eb57) も保持していることが分かると思います。 ©MIXI 89
  53. commit の仕組み ここまで紹介した 3つのオブジェクトに関する内容を踏まえて、コミットの仕組みを解説 していきます。 まずここまでの話を整理すると • commit オブジェクトは、その時点のリポジトリのルートにあたる tree

    オブジェクト を参照 • tree オブジェクトは、その時点の ディレクトリ配下の tree オブジェクトと blob オブ ジェクトへの参照を持つ • blob オブジェクトは、その時点のファイルのフルバックアップ => commit オブジェクトを参照し、そこから辿ることで commit 時点のリポジトリの状態 を完全に再現できる => スナップショット ©MIXI 92
  54. index について add について、「コミットに含めたいファイルをステージング(index)に登録してい る」という説明を⾒たことはあるかもしれません。 add の説明に⼊る前に、index について解説していきます。 index の情報は

    .git/index に記録されているので、オブジェクトと同じように⾒ていきま す。 Example $ cat .git/index tc:�9� -����_���/git-internals/first-commit.txtg� -��>g� -��>f�����] �b��3�:9]����x�git-internals/second-commit.txtTREE?3 1 *Z�Vi�1&XS����8tgit-internals2 0 +ζ����>�bK�d�� �Wv8l��Y'9� nY*>���% ©MIXI 95
  55. index について バイナリファイルなので、そのまま cat するだけだと⽂字化けしてしまいます。 index の中⾝を⾒るためのサブコマンドも⽤意されているので、そちらを使います。 Example $ git

    ls-files --stage 100644 182366232745d29b616008e23d5ac365f51df489 0 README.md 100644 da0d74633ad2023909aea38ce45fcaf1b2fa0e2f 0git-internals/first-commit.txt 100644 c2f0160862bf1fbc7f338d3a395d9880f5ef7881 0 git-internals/second-commit.txt 左から、ファイルの種類+パーミッション、blob ハッシュ、コンフリクトフラグ、ファイ ル名が並んでいます。 index には、現在参照しているバージョン(コミット)で管理対象(ステージングエリア 含め)の全ての blob オブジェクトへの参照をもっています。 ©MIXI 96
  56. add の内部動作 例えば、適当にファイルを作成してaddすると、indexは以下のように更新されています。 Example $ mkdir temp $ echo hoge

    > temp/hoge.txt $ git add temp/hoge.txt $ git ls-files --stage 100644 182366232745d29b616008e23d5ac365f51df489 0 README.md 100644 da0d74633ad2023909aea38ce45fcaf1b2fa0e2f 0git-internals/first-commit.txt 100644 c2f0160862bf1fbc7f338d3a395d9880f5ef7881 0 git-internals/second-commit.txt 100644 2262de0c121f22df8e78f5a37d6e114fd322c0b0 0 temp/hoge.txt temp/hoge.txtがindexに追加されていることがわかります。また、blobハッシュも記録 されており、該当Keyを⾒にいくとblobオブジェクトも⽣成されていることが分かると思 います。 すでにあるファイルを編集した場合も、新しいblobオブジェクトが⽣成され、indexが そのハッシュ値に書き変わります。 ©MIXI 98
  57. commit の内部挙動 次に、commit した時に起こる内部挙動は、以下の通りです。 • • • index から tree

    オブジェクトを⽣成 commit オブジェクトを⽣成 HEAD を新しい commit ハッシュに書き換え それぞれ詳しく解説していきます。 ©MIXI 99
  58. commit の内部挙動 ~tree オブジェクトの作成~ tree オブジェクトの作成はこの段階で⾏われます。 commit すると、新たに作成されたディレクトリに対する tree オブジェクトだけでなく、

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

    commit オブジェクトに記録する情報(再掲) • リポジトリのルートディレクトリのtreeオブジェクトのハッシュ値(Key) • 親commitのハッシュ値 • committerとauthorのタイムスタンプ‧名前‧メールアドレス • コミットメッセージ 先述の通り、リポジトリのルートにあたるtreeオブジェクトを参照しているため、そこか らリポジトリ全体をたどることができます。 ©MIXI 101
  60. commit の内部挙動 ~HEAD を新しい commit ハッシュに書き換え~ 最後に、現在参照しているコミットを指す .git/HEAD を必要に応じて書き換えます。 .git/HEAD

    についても中⾝を⾒てみます。 $ cat .git/HEAD ref: refs/heads/main Example refs/heads/main(mainブランチ)を参照しているとあるのでそちらを辿って⾒ます。 $ cat .git/refs/heads/main 20226ccdeaac3afd6030b6c47565aeb2edf88d9d $ git cat-file -p 20226ccdeaac3afd6030b6c47565aeb2edf88d9d Example ……[update]update README to explain Git internal structure ここに記録されているのが commit ハッシュです。ここを新しいコミットのハッシュ値 (commit オブジェクトのKey)に書き換えることで、コミット操作を完了します。 ©MIXI 102
  61. refs について ~light-weight tag~ light-weight tag を作成して確認します。タグは .git/refs/tags/ に保存されます。 Example

    $ git tag test-1 $ git log -n 1 --oneline 20226cc (HEAD -> main, tag: test-1, origin/main, origin/HEAD) [update]update README to explain Git internal structure $ cat .git/refs/tags/test-1 20226ccdeaac3afd6030b6c47565aeb2edf88d9d tag を付与した時点のコミットハッシュが記録されていることがわかると思います。 ©MIXI 105
  62. refs について ~branch~ 次に branch です。こちらは基本的には 特定の commit を指す参照です。 この点は

    light-weight tag とよく似ています。 違いとしては、保存場所が .git/refs/heads 以下になっている点と、branch の場合はその branch 上で commit を⾏うと、branch が指す commit が⾃動的に新しい commit へ更 新されることです。 ※「commitの内部挙動 ~HEADを新しい commit ハッシュに書き換え~」で解説した通り $ cat .git/refs/heads/main 20226ccdeaac3afd6030b6c47565aeb2edf88d9d Example branch の実態も、単に特定のコミットへのポインタなので、branch を削除してしまった としても焦る必要はありません。 ©MIXI 106
  63. refs について ~HEAD~ 最後に HEAD です。HEAD は先ほども⾔った通り、現在の commit を指す refs

    です。 .git/HEAD に保存されており、commit や checkout/switch などで書き変わります。ま た、branch 名で checkout/switch した時はコミットハッシュではなく branch の場所が 書き込まれるようになっています。 ©MIXI 107
  64. commit の仕組み(再掲) ここまでで、commit に関連する全てのオブジェクトと、仕組みを解説してきました。 commit の流れを再度まとめておきます。 • • • ©MIXI

    コードを編集する 編集したコードをaddする ◦ add したファイルの blob オブジェクトの⽣成 ◦ index の更新 commitする ◦ リポジトリ全体の tree オブジェクトの⽣成 ◦ commit オブジェクトを⽣成 ◦ HEAD の書き換え 108
  65. reset コマンド reset では、基本的には以下の 3 つを書き換えることでそれらを実現しています。 • ワークツリー(作業ディレクトリ) • index

    • HEAD おおまかには soft, mixed, hard の 3 種類のオプションがあり、指定した commit ハッ シュに向けて、それぞれの内容を書き換える。 HEAD git reset --soft index <commit ハッシュ> 書き換える git reset --mixed <commit ハッシュ> 書き換える 書き換える git reset --hard 書き換える 書き換える ©MIXI <commit ハッシュ> ワークツリー 書き換える 111
  66. reset コマンド どのオプションでも HEAD の書き換えはある。 なお、checkout/switch と異なり、reset では branch の参照先も書き換わる。

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

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

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

    reset の場合 first commit README.md に 「main」と追記 main.txt を追加 HEAD main develop develop.txt を追加 ©MIXI README.md に 「develop」と追記 115
  70. reset コマンド ここまで解説した機能があることで、前述した⽤途を実現できます。 (再掲) • commit の取り消し ◦ 1 つ前の

    commit ハッシュに branch を向けることで、最新のコミットをなかっ たことにできる(branch の参照先を変えられる機能があるため) • add の取り消し ◦ git reset --mixed HEAD とすると、index を HEAD の状況に戻せるので、add を 取り消すことができる • 作業の取り消し ◦ git reset —hard HEAD とすると、ワークツリーの状況を HEAD に戻せる ◦ ※現在では、restore の⽅が推奨 ©MIXI 116
  71. reset コマンド add, commitの取り消しについて補⾜ あくまで reset で⾏われているのは以下の操作です。 HEAD git reset

    --soft index <commit ハッシュ> 書き換える git reset --mixed <commit ハッシュ> 書き換える 書き換える git reset --hard 書き換える 書き換える <commit ハッシュ> ワークツリー 書き換える add や commit の内部動作で⾏なっていたことを完全に無かったことにできているでしょ うか? ©MIXI 117
  72. まとめ 以降はこの後の git challenge で取り組んでください。 ここまでの内容が分かっていれば、講義の最初に挙げた以下の問題が起きた時にも、 焦らず対処できるはずです。 • • •

    ©MIXI ブランチをマージ前に間違えて消してしまった! コミットを誤って消してしまった! コミット前(ステージングエリア)のファイルを消してしまった! 118