Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

実践 Git - 低レベルに知る Git

25,898 views

Published on

gumistudy@福岡 vol.2 http://atnd.org/events/27933
original slide: http://youhei.github.io/showoff-git-lowlevel

Published in: Technology
  • Be the first to comment

実践 Git - 低レベルに知る Git

  1. 1. 実践 Git低レベルに知る Git
  2. 2. 本⽇のアジェンダ⾃⼰紹介スライドのスコープについてリポジトリオブジェクトデータベースインデックスリファレンスまとめ
  3. 3. <⾃⼰紹介>
  4. 4. 新⽥ 洋平2012年3⽉ 福岡オフィス⼊社アプリケーションエンジニア福岡に来て昨⽇でまだ⼆ヶ⽉仲良くしてね
  5. 5. ソーシャルメディアとかblog@youheifb.com/youheigit.io/youhei
  6. 6. Git 使⽤歴前職までは Subversion 中⼼前職の2つのプロジェクトで実験的に導⼊初⼼者2名でそれほどノウハウも溜まらずちゃんと使い出したのは gumi に⼊ってから
  7. 7. </⾃⼰紹介>
  8. 8. みなさん Git 使ってますか?
  9. 9. Git ってなんかわかりにくく ないですか?
  10. 10. ⾃分はわかりにくいなあと 感じていました
  11. 11. はてブ, Twitter に溢れる 初⼼者向け Tips
  12. 12. 各地で開催される Git 勉強会
  13. 13. Git のわかりにくさを解消す るための様々なツール
  14. 14. GUI
  15. 15. sourcetreeapp.com
  16. 16. git-tower.com
  17. 17. CLI
  18. 18. git-flow$ git flow init$ git flow feature start branch_name$ git flow feature end branch_name$ git flow hotfix$ git flow release
  19. 19. legit - Git Workflow for Humans$ git switch <branch>$ git sync$ git publish$ git unpublish$ git harvest$ git sprout$ git graft$ git branches
  20. 20. 便利ツールは諸刃の剣これら⾼機能なツールは Git を使いやすくしてくれますが、「本質 的な理解」をせずとも使えてしまう諸刃の剣でもあります。
  21. 21. 「本質的な理解」に近付くには⾼レベルの抽象化されたコマンドやオプションを使いこなせても Git がわかった感じがしない対症療法的な解決になりがちググってコマンド打ってみる、とかそれは Git の内部を理解していないからしかしコマンドやオプションは全て理解するには数がとても多いデータに焦点を当てると覚えることが少なそう
  22. 22. と、いうことでデータ構造の観点から Git を調べてみ ました
  23. 23. Git を実践的に使う上で⽋かせない ⾼レベルな機能 分散リポジトリ add --patch merge, pull --rebase stash, reflog rebase -i による歴史の改変
  24. 24. これらはこのスライドのスコープ外 です ⼀旦お忘れください (実践 Git と⾔っておきながら...)
  25. 25. リポジトリ .git
  26. 26. git の基本構成要素.git は working tree 以外の情報全てをもつGit をボトムアップから理解するより引⽤
  27. 27. リポジトリの作成$ mkdir sandbox && cd sandbox$ git init$ tree .git.git├── HEAD # 現在チェックアウトしてるブランチ├── config├── description├── hooks│ └─各種 hook スクリプト├── info│ └── exclude├── objects # オブジェクトデータベース│ ├── info│ └── pack└── refs # リファレンス(ブランチ, タグなど) └── heads └── tags
  28. 28. オブジェクトデータベース .git/objects
  29. 29. .git/objects の特徴変更(デルタ)ではなくスナップショット各々のコミットに対するツリー構造とデータをまるごと保管する
  30. 30. オブジェクトの種類オブジェクトデータベース(.git/objects)に格納されるオブジェクト blob tree commit tag (今回省略します)
  31. 31. blob object
  32. 32. データそのものを指す オブジェクト
  33. 33. オブジェクト ID は SHA-1 ハッシュ$ echo Hello, World! > greeting$ git hash-object greeting8ab686eafeb1f44702738c8b0f24f2567c36da6d
  34. 34. blob はファイル名に関係なく 中⾝が同じならば同じ ID$ echo Hello, World! > greeting2$ git hash-object greeting greeting28ab686eafeb1f44702738c8b0f24f2567c36da6d8ab686eafeb1f44702738c8b0f24f2567c36da6d
  35. 35. オブジェクトはオブジェクトデータベースに ファイルで管理される 先頭2桁のディレクトリ名/残り38桁のファイル名$ git add greeting$ tree .git.git # (⾊々省略)├── index # インデックス└── objects └─ 8a └── b686eafeb1f44702738c8b0f24f2567c36da6d$ git cat-file -t 8ab6blob$ git cat-file blob 8ab6Hello, World!
  36. 36. オブジェクトは読み込み権限で作成される ⼀度作成されたオブジェクトは上書きされないことを⽰唆している$ stat -c %A .git/objects/8a/b686eafeb1f44702738c8b0f24f2567c36da6d-r--r--r--
  37. 37. 同じ内容の blob を追加してもオブジェクトは置換されない 更新時刻は変わらないので置換されていないことがわかる $ stat -c %y .git/objects/8a/b686eafeb1f44702738c8b0f24f2567c36da6d 2012-04-23 09:43:12.000000000 +0900 $ git add greeting2 $ stat -c %y .git/objects/8a/b686eafeb1f44702738c8b0f24f2567c36da6d 2012-04-23 09:43:12.000000000 +0900
  38. 38. 削除してもオブジェクトデータベースから 消えない$ git rm --cached greeting greeting2rm greetingrm greeting2$ git cat-file blob 8ab6Hello, World!
  39. 39. blob object についてわかったことオブジェクトは SHA-1 ハッシュ ID で⼀意になるblob はデータの中⾝のみで⼀意になるオブジェクトデータベースは追記のみで更新しない削除コマンドを実⾏しても実体は残るいわゆるイミュータブル(不変)なオブジェクト
  40. 40. tree object
  41. 41. blob にファイル構造を 与えるオブジェクト
  42. 42. tree はコミット時に作られる$ git add greeting$ git commit -m added my greeting.[master (root-commit) 77d0330] added my greeting. 1 file changed, 1 insertion(+) create mode 100644 greeting$ git cat-file commit HEAD # 最新コミットの中⾝をみるtree 2da064c4206cb1e94a20a99c2cd2e19f3d193b74author Youhei Nitta <me@youhei.jp> 1335212302 +0900committer Youhei Nitta <me@youhei.jp> 1335212302 +0900added my greeting.$ git cat-file -t 2da0tree
  43. 43. tree は blob や tree を保持している$ git ls-tree 2da0100644 blob 8ab686eafeb1f44702738c8b0f24f2567c36da6d greeting$ mkdir subdir && mv greeting2$ git add subdir$ git commit -m added sub directory.$ git ls-tree HEAD040000 tree 18e6d2abde0f316ff62e0c8093ca8f569910bf7d subdir100644 blob 8ab686eafeb1f44702738c8b0f24f2567c36da6d greeting$ git ls-tree 18e6100644 blob 8ab686eafeb1f44702738c8b0f24f2567c36da6d greeting2
  44. 44. tree object についてわかったこと構造や名前をもたない blob にファイルシステムとしての構造を与えるblob や tree を保管しているtree はコミットに保持される
  45. 45. commit object
  46. 46. ある時点でのスナップショットを ⽰すオブジェクト
  47. 47. tree のオブジェクト ID を持つ$ git cat-file commit HEADtree 680e36390174676a7343ec570f9f22d0632f4444parent 77d03308354257e850041fd2d10448fc3a2c4c8bauthor Youhei Nitta <me@youhei.jp> 1335213434 +0900committer Youhei Nitta <me@youhei.jp> 1335213434 +0900added sub directory.$ git ls-tree commit 680e040000 tree 18e6d2abde0f316ff62e0c8093ca8f569910bf7d subdir100644 blob 8ab686eafeb1f44702738c8b0f24f2567c36da6d greeting
  48. 48. 親コミットのオブジェクト ID を持つ(最初のコミットを除く)$ git cat-file commit HEADtree 680e36390174676a7343ec570f9f22d0632f4444parent 77d03308354257e850041fd2d10448fc3a2c4c8bauthor Youhei Nitta <me@youhei.jp> 1335213434 +0900committer Youhei Nitta <me@youhei.jp> 1335213434 +0900added sub directory.$ git cat-file -t 77d0commit$ git cat-file commit 77d0tree 2da064c4206cb1e94a20a99c2cd2e19f3d193b74author Youhei Nitta <me@youhei.jp> 1335212302 +0900committer Youhei Nitta <me@youhei.jp> 1335212302 +0900added my greeting.
  49. 49. マージコミットは⼆つの親コミットを持つ (少し⾼レベルに戻ります)$ git branch fukuoka$ git checkout fukuoka$ echo Hello, Fukuoka! > greeting2$ git add greeting2$ git commit -m added another greeting.$ git checkout master$ git merge fukuoka -m merged fukuoka branch.$ git cat-file commit HEADtree 2fb79db8e8b4ab0f704a056754b434ff2a5435b9parent ae3bc73b86e8ea701496122f4ea7ec5e29cab979parent 5d8fc0a8aef3930dac4347bdfda950cec83bde8cauthor Youhei Nitta <me@youhei.jp> 1335215713 +0900committer Youhei Nitta <me@youhei.jp> 1335215713 +0900merged fukuoka branch.
  50. 50. commit object についてわかったこと必ず tree を持っているつまりコミット時点でのツリーの完全な状態(スナップショット)を持っているparent を持っているマージコミットは parent を⼆つ持っているつまり parent を辿れば「履歴」を構成できる
  51. 51. Git の実体(エンティティ)は 基本的にはこれだけです とてもシンプルです
  52. 52. 残りの登場⼈物はふたつインデックスリファレンス
  53. 53. インデックス .git/index
  54. 54. .git/index次のコミットの準備をする場所バイナリファイルにパス、パーミッション、blob 値をもつ次の HEAD になる commit を⽣成するためのエリア
  55. 55. .git/index は tree の鋳型 Git をボトムアップから理解するより引⽤
  56. 56. リファレンス .git/refs
  57. 57. リファレンスとは覚えにくいオブジェクト ID の代わりに使う別名ローカルブランチ, リモートブランチ, タグ, HEAD は全てリファレンス
  58. 58. リファレンスの種類referencessymbolic referencesremote references (今回省略します)
  59. 59. branch は references$ cat .git/refs/heads/master41219f49d28b936482be893a6ca3b5a77443c78a$ git cat-file commit mastertree 2fb79db8e8b4ab0f704a056754b434ff2a5435b9parent ae3bc73b86e8ea701496122f4ea7ec5e29cab979parent 5d8fc0a8aef3930dac4347bdfda950cec83bde8cauthor Youhei Nitta <me@youhei.jp> 1335215713 +0900committer Youhei Nitta <me@youhei.jp> 1335215713 +0900Merge branch fukuoka$ git cat-file commit 41219f49d28b936482be893a6ca3b5a77443c78atree 2fb79db8e8b4ab0f704a056754b434ff2a5435b9parent ae3bc73b86e8ea701496122f4ea7ec5e29cab979parent 5d8fc0a8aef3930dac4347bdfda950cec83bde8cauthor Youhei Nitta <me@youhei.jp> 1335215713 +0900committer Youhei Nitta <me@youhei.jp> 1335215713 +0900Merge branch fukuoka
  60. 60. HEAD は symbolic references 他の references へのポインタで表現されている$ cat .git/refs/HEADref: refs/heads/master$ git symbolic-ref HEADrefs/heads/master$ git cat-file commit HEADtree 2fb79db8e8b4ab0f704a056754b434ff2a5435b9parent ae3bc73b86e8ea701496122f4ea7ec5e29cab979parent 5d8fc0a8aef3930dac4347bdfda950cec83bde8cauthor Youhei Nitta <me@youhei.jp> 1335215713 +0900committer Youhei Nitta <me@youhei.jp> 1335215713 +0900Merge branch fukuoka
  61. 61. tag も references$ git tag v0.0.1$ cat .git/refs/tags/v0.0.141219f49d28b936482be893a6ca3b5a77443c78a$ git cat-file commit v0.0.1tree 2fb79db8e8b4ab0f704a056754b434ff2a5435b9parent ae3bc73b86e8ea701496122f4ea7ec5e29cab979parent 5d8fc0a8aef3930dac4347bdfda950cec83bde8cauthor Youhei Nitta <me@youhei.jp> 1335215713 +0900committer Youhei Nitta <me@youhei.jp> 1335215713 +0900Merge branch fukuoka$ git cat-file commit 41219f49d28b936482be893a6ca3b5a77443c78atree 2fb79db8e8b4ab0f704a056754b434ff2a5435b9parent ae3bc73b86e8ea701496122f4ea7ec5e29cab979parent 5d8fc0a8aef3930dac4347bdfda950cec83bde8cauthor Youhei Nitta <me@youhei.jp> 1335215713 +0900committer Youhei Nitta <me@youhei.jp> 1335215713 +0900Merge branch fukuoka
  62. 62. tag と branch の違い実はほとんど同じbranch は commit に合わせて変動する逆に tag は変動しない branch といえる
  63. 63. 以上が、Git を構成する要素の(ほぼ)全てですリポジトリオブジェクトデータベースインデックスリファレンス
  64. 64. ここまでの低レベルな観点だけで、 下記の⾼レベルな視点に ⾃分なりの回答ができるはずですいくら分散しても⽭盾が発⽣しない理由ブランチの切り替えが⾼速な理由reflog で過去のどの時点にも戻れる理由差分はどこから取り出しいつ計算するか推測SHA-1 ハッシュ値が衝突時に Git はどう振る舞うか推測
  65. 65. おまけ SHA-1 ハッシュ値の衝突について⼩噺SHA-1 の衝突を⾒るにはどうしたらいいのか、ひとつの例をごらんに⼊れましょう。地球上の⼈類 65 億⼈が全員プログラムを書いていたとします。そしてその全員が、Linux カーネルのこれまでの開発履歴 (100 万の Git オブジェクト) と同等のコードを⼀秒で書き上げ、⾺⿅でかい単⼀の Git リポジトリにプッシュしていくとします。これを五年間続けたとして、SHA-1オブジェクトの衝突がひとつでも発⽣する可能性がやっと 50% になります。それよりも「あなたの所属する開発チームの全メンバーが、同じ夜にそれぞれまったく無関係の事件で全員オオカミに殺されてしまう」可能性のほうがよっぽど⾼いことでしょう。 ProGit 6.1 リビジョンの選択 より
  66. 66. まとめgit のデータ構造はとてもシンプル低レベルな視点を持つと⾼レベルな機能・問題は⾃然とわかるようになる
  67. 67. 参考資料(掘り下げたい⼈向け)Git をボトムアップから理解するProGit 9. Git の内側Wrangling Git⼊⾨ Git 2章 git の基本概念Git によるバージョン管理 13章 Git リポジトリの中⾝を⾒るgitcore-tutorial(7)git(1): LOW-LEVEL COMMANDS
  68. 68. We are hiring!!では低レベルな技術者を募集しています!
  69. 69. 質疑応答

×