モデルから知るgit

90
モデルから知るGit 201139本間雅洋 (id:hiratara)

Upload: masahiro-honma

Post on 12-May-2015

10.455 views

Category:

Documents


7 download

DESCRIPTION

Git初心者向けの解説です。図が中心。

TRANSCRIPT

モデルから知るGit2011年3月9日

本間雅洋 (id:hiratara)

自己紹介• 本間雅洋 (id:hiratara)

• 苫小牧市出身

• 仕事はPerl

趣味でPython、Java、Haskellなど

• 実用Gitの共訳に参加

レジュメ

• Gitを使ってみる

• ローカルリポジトリ

• 作業ディレクトリ

• リモートリポジトリ

俯瞰図

リポジトリ作業dir

リポジトリ作業dir

bareリポジトリ

リポジトリ作業dir

hoge/.git/configrefs...

hoge/.gitignorehoge.txt...

hoge.git/configrefs...

Gitを使ってみる

Gitとは

• バージョン管理

• Linus氏作、現在のメンテナは濱野氏

• 分散型で、速度重視

Gitを試す環境作り

$ mkdir your-repo$ cd your-repo/$ git init

.git/ 以下のファイル• .git/config

git config で扱うファイル。手で編集してもよい。

• .git/refs/...

ブランチやタグ。意識するとブランチの指定が楽。

ローカルリポジトリ

コミットとツリーAuthor: hirataraDate: 2/25 13:43:42

typoを修正

index.htmlimages/flower.gifcss/index.cssjs/index.jsツリー

コミット

マージコミット

コミットオブジェクト• 親コミットへのポインタを持つ

(履歴を鎖上に結ぶ)

• 親コミットが2つあればマージ

• ツリー(のroot)へのポインタを持つ

• 日時、作者、コメントを含む

ツリーオブジェクト• ある時点のコンテンツのスナップショット

• 厳密には、以下の組み合わせツリー = ディレクトリ

ブロブ = ファイル index.html

flower.gif index.js

gitとsvnのモデル

最新

DCBA

SVN

Git

差分

差分

差分

gitとsvnのマージ

最新

SVN

Git

差分

差分

差分

差分

分岐は大差なし

git merge --squash相当

gitとsvnの履歴操作• gitは履歴を変更するコマンドが豊富

• gitはIDが連番でない

→ポインタのみ変えればよい

• 各個人が履歴を持っている→気軽に編集してよい

gitのブランチ• モデル内のコミットにつけた単なるラベル

• ラベルがあると、コミットの指定が楽→特にマージのときは、先頭が欲しい

• ラベルがなくてもIDで直接指定は可能

ブランチ・タグ

heads/master

heads/topic ブランチtags/0.9973

タグ remotes/origin/master 追跡ブランチ

ブランチ=refs/heads

• コミットへのrefは、全て.git/refsにある

• .git/refs/tags/ タグ

• .git/refs/heads/ ブランチ

• .git/refs/remotes/ 追跡ブランチ

refの検索ルール• .git/名前

• .git/refs/名前

• .git/refs/tags/名前

• .git/refs/heads/名前

• .git/refs/remotes/名前

refの検索の例• 以下の2つがあるとき

heads/hiratara/master

remotes/hiratara/master

• hiratara/master だとローカルブランチ

• remotes/hiratara/master が追跡ブランチ

リモート名

コミットの例

mastertopic

git commit(1)

1

master

topic

git commit(2)

1 2

topic

master

マージの例

1 2

topic

master

git merge

1 2

topic

master

git commit(3)

1 2

3

topic

master

再びtopicを修正

1 2

3

topic

master

git commit(4)

1 2

3

4

topic

master

コミットのID

• ツリー(ある時点でのコンテンツ)に対してIDをつける→IDが一緒ならコンテンツも一緒

• コミットに対してIDをつける

→ポインタまで含めたID

→IDが一緒なら一連の履歴が完全一致

IDはSHA1

• こんなの

• ちょっとでも違う物には違うID

コミットコメントが違うだけでも

% git log --format=onelineb825e9d877e19804389494c349f4feb6e61af698 4th7eb449172702e32d08bb69a5527f0f99f157aa86 3rd99e990675c72155d1a8d2b5059b954bd852f53ca seconde282d0c2a31318f35eca789372c4579c53cfd292 initial

コミットは不変

• 「ちょっとでも違う物には違うID」

→IDを変えずに変更することは不可能

→コミットはイミュータブル

• Gitのモデルを堅固にしている

リベースの例

A

B C

topic

master

git rebase

A

B C

topic

イミュータブルなので、B、Cはそのまま

master

B’ C’

チェリーピックの例

A

B C

topic

master

git cherry-pick B

A

B C

topic

B'

master

git cherry-pick C

A

B C

topic

B' C'

master

履歴書換の例

A B C

master

rebase -i HEAD~3

A B C

B' C'

master

A'

イミュータブルなので、A・B・Cはそのまま

reflog

• タグのないコミットを探すのに便利

• git reflog show master

masterが指したコミットの履歴% git reflog show master835beaf master@{0}: rebase -i (finish): refs/heads/master onto 7e1871f29f2b87 master@{1}: commit: Added C57cd6f6 master@{2}: commit: Added Bc958196 master@{3}: commit: Added A7e1871f master@{4}: commit (initial): initial

コミットCを発見

リセットの例

A B C

B' C'

master

A'

git reset C

A B C

B' C'

master

A'

リバートの例

A B C

master

git revert A

A B C -A

master

特殊な履歴

mastertopic

同じ修正をcommit

master

ツリーは共有

コミットは別topic

git merge master

master

topic

作業ディレクトリ

.git ディレクトリ3つの領域

リポジトリ

インデックス 作業ディレクトリ

D

D

D

CBA

master

topic

インデックス

• リポジトリと作業ディレクトリの中間

• コンテンツの仮保存場所

• 「staged」「cached」とも言われる

.git ディレクトリ編集をする

リポジトリ

インデックス 作業ディレクトリ

D

D

D’

CBA

master

topic

.git ディレクトリgit add

リポジトリ

インデックス 作業ディレクトリ

D’

D

D’

CBA

add

master

topic

.git ディレクトリ再び編集

リポジトリ

インデックス 作業ディレクトリ

D’

D

D’’

CBA

master

topic

.git ディレクトリgit add

リポジトリ

インデックス 作業ディレクトリ

D’’

D

D’’

CBA

add

master

topic

.git ディレクトリgit commit

リポジトリ

インデックス 作業ディレクトリ

D’’

D

D’’

CBA D’’

commit

master

topic

ポイント

• D’ はリポジトリに追加されていない→洗練した変更のみをリポジトリへ

• 逆の言い方をすれば、インデックスを介さないとコミットできない

.git ディレクトリ3領域とコマンド

リポジトリ

インデックス 作業ディレクトリ

D’

D

D’’

CBA

commitcommit -acommit filename

add

master

topic

.git ディレクトリチェックアウトの例(1)

リポジトリ

インデックス 作業ディレクトリ

D

D

D

CBA

topic

master

.git ディレクトリgit checkout master

リポジトリ

インデックス 作業ディレクトリ

C

D

C

CBA

topic

master

.git ディレクトリチェックアウトの例(2)

リポジトリ

インデックス 作業ディレクトリ

D'

D

D''

CBA

topic

master

.git ディレクトリgit checkout master .

リポジトリ

インデックス 作業ディレクトリ

C

D

C

CBA

topic

master

.git ディレクトリgit checkout .

リポジトリ

インデックス 作業ディレクトリ

D'

D

D'

CBA

topic

master

.git ディレクトリリセットの例(1)

リポジトリ

インデックス 作業ディレクトリ

C'

D

C''

CBA

topic

master

.git ディレクトリgit reset --soft topic

リポジトリ

インデックス 作業ディレクトリ

C'

D

C''

CBA

topic

master

.git ディレクトリgit reset topic

リポジトリ

インデックス 作業ディレクトリ

D

D

C''

CBA

topic

master

.git ディレクトリgit reset --hard topic

リポジトリ

インデックス 作業ディレクトリ

D

D

D

CBA

topic

master

リモートリポジトリ

リモートの基本

• 触れるのはローカルリポジトリだけ(origin/master も実はローカルにある)

• 転送を行うのは、git fetchとgit pushだけ

リモートリポジトリ

A masterB C

A masterB C X

[email protected]:him/hoge.git

~/git-repos/hoge

直接リモートのデータは参照できない

D

git remote add

A masterB C

A masterB C X

github => [email protected]:him/hoge.git

~/git-repos/hoge

D

git remote add github git@...

git fetch

A masterB C

A masterB C X

github => [email protected]:him/hoge.git

~/git-repos/hoge

D

github/masterD

git fetch github(又はgit remote update)

refspec• 転送元・先を指定するフォーマット

• push, fetch で必要(fetchでは省略することが多い)

heads/fromheads/to

heads/toheads/from

github

git push github from:to

git fetch github from:to※普通はheads以下にはしない

fetchとrefspec

• git remote addした時のデフォルト[remote "github"]fetch = +refs/heads/*:refs/remotes/github/*

• 「+」はforceの意

mergeかrebaseする

A masterB C

A masterB C X

github => [email protected]:him/hoge.git

~/git-repos/hoge

D

github/masterD

X`

git rebase github/master

git push

A masterB C

A masterB C X

github => [email protected]:him/hoge.git

~/git-repos/hoge

D

github/masterD

X`

X`

git push github

push と refspec

• refspecを省略した時の振舞いに注意→"カレントブランチをpush"ではない

• push.default で振舞いを変えられるnothing, matching, tracking, current

• remote.<name>.pushは使ったことない

(F/Wの都合でfetch出来ない時など利用)

fetchとpullとpush(1)

heads/masterheads/another

remotes/github/masterremotes/github/anotherheads/masterheads/local-branchheads/another

github => [email protected]:him/hoge.git

~/git-repos/hogegit fetch githubremote.<name>.fetchによる

fetchとpullとpush(2)

heads/masterheads/another

remotes/github/masterremotes/github/anotherheads/masterheads/local-branchheads/another

github => [email protected]:him/hoge.git

~/git-repos/hoge git pull = fetch + merge

branch.<name>.mergeによる

branch.<name>.remoteによる

fetchとpullとpush(3)

heads/masterheads/another

remotes/github/masterremotes/github/anotherheads/masterheads/local-branchheads/another

github => [email protected]:him/hoge.git

~/git-repos/hogegit push githubpush.default=matchingによる

githubによる開発の例

topic1 master

masterorigin/topic1

origin/master

hanakoがtaroをclone

topic1 master

masterorigin/topic1

origin/master

origin/topic1

origin/master

hanakoがtopic2を開発

topic1 master

masterorigin/topic1

origin/master

origin/topic1

origin/master

topic2

hanakoがtaroをfork

topic1 master

masterorigin/topic1

origin/master

origin/topic1

origin/master

topic2

topic1 master

git remote -f add

topic1 master

masterorigin/topic1

origin/master

origin/topic1

origin/master

topic2

topic1 master

hanako/topic1

hanako/master

git push hanako topic2

topic1 master

masterorigin/topic1

origin/master

origin/topic1

origin/master

topic2

topic1

hanako/topic1

hanako/mastertopic2

master

hanako/topic2

tarouへpull-req

topic1 master

masterorigin/topic1

origin/master

origin/topic1

origin/master

topic2

topic1

hanako/topic1

hanako/mastertopic2

master

pull request

hanako/topic2

taroがremote add

topic1 master

masterorigin/topic1

origin/master

origin/topic1

origin/master

topic2

topic1

hanako/topic1

hanako/mastertopic2

master

hanako/topic1

hanako/master

hanako/topic2

hanako/topic2

merge hanako/topic2

topic1 master

masterorigin/topic1

origin/master

origin/topic1

origin/master

topic2

topic1

hanako/topic1

hanako/mastertopic2

master

hanako/topic1

hanako/master

hanako/topic2

hanako/topic2

git push origin master

topic1

masterorigin/topic1

origin/master

origin/topic1

origin/master

topic2

topic1

hanako/topic1

hanako/mastertopic2

master

hanako/topic1

hanako/master

hanako/topic2

hanako/topic2

masterorigin/master

データの流れ

開発・マージは全てローカルレポジトリで起こる

github側は参照されるだけ

まとめ• gitのモデルはシンプルで、svnよりも遥かに扱いやすい

→自由に望みの履歴を作れる

• 対照的にgitのコマンドは洗練されておらず、ドキュメントは手放せない