Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Git Internals

コミットとブランチ編

Dennis Gosnell

this presentation online

親コミットと子コミットの話

コミットとコミットの関係と、ブランチとコミットの関係を詳しく調べます。

今日話すこと

  • git branch
  • git checkout
  • git reset
  • git merge
  • git rebase

テストレポジトリを作成

$ mkdir testrepo && cd testrepo
$ git init .
Initialized empty Git repository in ~/testrepo/.git/
$ git config user.name "Test User"
$ git config user.email "testuser@example.com"

テストコミット

$ touch README
$ git add .
$ git commit -m "Initial commit."
[master (root-com) 54b450] Initial commit.
 0 files changed
  create mode 100644 README

前回の復習①

$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
54b450dd7d7c8280040569fc7b5e4637883e76c2
$ cat .git/objects/54/b450dd7d7c82*
...

前回の復習②

$ tree .git/
.git/ ├── HEAD ( -> refs/heads/master ) ├── objects/ │   ├── 54/ │   │   ├── 3b9bebdc6bd5c4b22136034a95dd097a57d3dd │   │   └── b450dd7d7c8280040569fc7b5e4637883e76c2 │   └── e6/ │      └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 └── refs/    ├── heads/    │   └── master ( -> objects/54/b450dd7d7c82800... )    └── tags/

子コミット

$ echo "hogehoge" >> README
$ git add README
$ git commit -m "Child commit."
[master ac07971] Child commit.
 1 file changed, 1 insertion(+)

.git/HEAD

.git/refs/heads/master

どう変わった?

最初のコミット:HEAD

$ cat .git/HEAD
ref: refs/heads/master

二番目のコミット:HEAD

$ cat .git/HEAD
ref: refs/heads/master

コミットを何回しても、HEADが参照しているブランチが変わらない

最初のコミット:
masterブランチ

$ cat .git/refs/heads/master
54b450dd7d7c8280040569fc7b5e4637883e76c2

二番目のコミット:
masterブランチ

$ cat .git/refs/heads/master
ac0797189547f3f0cdcf39cb170b16d2344aeaf3

コミットをするたびに、masterブランチが参照しているコミットが変わる

親コミット and 子コミット

$ git log --pretty=raw
commit: ac07971895
parent: 54b450dd7d
author: <testuser@example.com> Jul 13 14:51:49

    Child commit.

commit: 54b450dd7d
author: <testuser@example.com> Jul 8 18:36:36

    Initial commit.

子コミットが親コミットを参照している

コマンド紹介

git branch

全部のブランチを表示

$ git branch --verbose --all
* master ac07971 Child commit.
  • masterブランチしかない
  • コミットハッシュとコミットメッセージも見れる

ブランチ追加

$ git branch newbranch
$ git branch --verbose --all
* master     ac07971  Child commit.
  newbranch  ac07971  Child commit.
  • newbranchが作られた
  • masterと同じコミットを参照している

.git確認①

$ tree .git/
.git/ ├── HEAD ├── objects │   ├── 54 │   │   └── b450dd7d7c │   └── ac │      └── 0797189547 └── refs    └── heads       ├── master       └── newbranch
  • newbranchが作られた

.gitで確認②

$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
ac0797189547f3f0cdcf39cb170b16d2344aeaf3
  • HEADはmasterブランチを参照
  • masterはさきの子コミットを参照

.gitで確認③

$ cat .git/refs/heads/newbranch
ac0797189547f3f0cdcf39cb170b16d2344aeaf3
  • .git/refs/heads/newbranchが作られた
  • masterと同じコミットを参照している

$ tree .git/
.git/ ├── HEAD ( -> refs/heads/master ) ├── objects │   ├── 54 │   │   └── b450dd7d7c │   └── ac │      └── 0797189547 ( 親: -> objects/54/b450dd7d7c ) └── refs    └── heads       ├── master ( -> objects/ac/0797189547 )       └── newbranch ( -> objects/ac/0797189547 )

またコミットしてみよう

$ echo foobar >> README
$ git add README
$ git commit -m "Second child commit."
[master 22c3956] Second child commit.
 1 file changed, 1 insertion(+)

git log

$ git log --graph --decorate --all 
* commit 22c39561 (HEAD, master)
| Date:   Fri Jul 18 18:25:20 2014 +0900
|     Second child commit.
|
* commit ac079718 (newbranch)
| Date:   Fri Jul 11 14:51:49 2014 +0900
|     Child commit.
|
* commit 54b450dd
  Date:   Tue Jul 8 18:36:36 2014 +0900
      Initial commit.

.gitで確認④

$ cat .git/refs/heads/newbranch
ac0797189547f3f0cdcf39cb170b16d2344aeaf3
$ cat .git/refs/heads/master
22c395616a88b1e845057ad2775399a1853d4010
  • .git/refs/heads/newbranchが作られた
  • masterと同じコミットを参照している

新しいブランチを使ってみよう!

git checkout

$ git checkout newbranch
Switched to branch 'newbranch'
$ cat .git/HEAD
ref: refs/heads/newbranch
$ cat .git/refs/heads/newbranch
ac0797189547f3f0cdcf39cb170b16d2344aeaf3
$ cat .git/refs/heads/master
22c395616a88b1e845057ad2775399a1853d4010
  • HEADがnewbranchを参照するようになった
  • masterは特に変わっていない

newbranchにコミット

$ echo testtest >> README
$ git add README
$ git commit -m "Commit on newbranch."
[newbranch 163e533] Commit on newbranch.
 1 file changed, 1 insertion(+)

.git/で確認

$ cat .git/HEAD
ref: refs/heads/newbranch
$ cat .git/refs/heads/newbranch
163e533db99cf9c8bc1f30222e47975840ae2883
$ cat .git/refs/heads/master
22c395616a88b1e845057ad2775399a1853d4010
  • newbranchは新しいコミットを参照している
  • master、HEADは特に変わっていない

git checkout

  • HEADが参照しているブランチを変えられる

ちなみに

ブランチだけじゃなくて任意のコミットをcheckoutすることもできる

$ git checkout 54b450dd
Note: checking out '54b450dd'.

You are in 'detached HEAD' state.
...
$ cat .git/HEAD
54b450dd7d7c8280040569fc7b5e4637883e76c2

HEADだけじゃなくてブランチも移動しよう!

git reset

新しいブランチ作成

$ git branch test
$ cat .git/HEAD
ref: refs/heads/newbranch
$ cat .git/refs/heads/newbranch
ac0797189547f3f0cdcf39cb170b16d2344aeaf3
$ cat .git/refs/heads/master
22c395616a88b1e845057ad2775399a1853d4010
$ cat .git/refs/heads/test
ac0797189547f3f0cdcf39cb170b16d2344aeaf3

checkout

$ git checkout test
Switched to branch 'test'
$ cat .git/HEAD
ref: refs/heads/test
$ cat .git/refs/heads/newbranch
ac0797189547f3f0cdcf39cb170b16d2344aeaf3
$ cat .git/refs/heads/test
ac0797189547f3f0cdcf39cb170b16d2344aeaf3
  • HEADがtestを参照するようになった

masterが参照しているコミットに、testを参照させる

reset

$ git reset --hard master
HEAD is now at 22c3956 Second child commit.
$ cat .git/HEAD
ref: refs/heads/test
$ cat .git/refs/heads/test
22c395616a88b1e845057ad2775399a1853d4010
$ cat .git/refs/heads/master
22c395616a88b1e845057ad2775399a1853d4010
  • testも22c395616を参照している

resetのフラグ

  • --soft
  • --mixed
  • --hard
  • ...

git merge...

...の話はしません。

聞きたい人いますか?

今日の最後のコマンド

一番怖いと言われているコマンド

git rebase

まずレポジトリーを整理

$ git checkout master
Switched to branch 'master'
$ git branch -D newbranch
Deleted branch newbranch (was 163e533).
$ git branch -D test
Deleted branch test (was 22c3956).
  • newbranchとtestブランチを削除

ブランチ削除確認

$ tree .git/refs
.git/refs/ ├── heads │   └── master └── tags
  • newbranchとtestブランチは.git/refs/から消えている

test2ブランチ作成

$ git branch test2

masterにテストコミット

$ echo "hello1" >> master-test-file 
$ git add master-test-file
$ git commit -m 'master commit 1'
[master b27026d] master commit 1
 1 file changed, 1 insertion(+)
 create mode 100644 master-test-file
$ echo "hello2" >> master-test-file 
$ git add master-test-file
$ git commit -m 'master commit 2'
[master 55970ec] master commit 2
 1 file changed, 1 insertion(+)

test2にテストコミット

$ git checkout test2
Switched to branch 'test2'
$ echo "foo1" >> test2-test-file 
$ git add test2-test-file
$ git commit -m 'test2 commit 1'
[test2 491b512] test2 commit 1
 1 file changed, 1 insertion(+)
 create mode 100644 test2-test-file
$ echo "foo2" >> test2-test-file 
$ git add test2-test-file
$ git commit -m 'test2 commit 2'
[test2 e43ab74] test2 commit 2
 1 file changed, 1 insertion(+)

rebase

$ git rebase master
First, rewinding head...
Applying: test2 commit 1
Applying: test2 commit 2
$ ls
master-test-file  README  test2-test-file
$ git log --oneline
dc2421d test2 commit 2
910a5a7 test2 commit 1
55970ec master commit 2
b27026d master commit 1
22c3956 Second child commit.
ac07971 Child commit.
54b450d Initial commit.

コミットハッシュを注目

$ git log --oneline
dc2421d test2 commit 2
910a5a7 test2 commit 1
  • コミットが書き換えられている

rebase

  • 2つのブランチが分岐された時点から、現在のブランチを切り離して、もうひとつのブランチの最新のコミットに移動させる

レビュー

git branch
新しいブランチを作成
git checkout
HEADが参照しているブランチを変更
git reset
現在のブランチが参照しているコミットを変更
git rebase
ブランチごとを移住

fin

Use a spacebar or arrow keys to navigate