2018年以降の記事はGitHub Pagesに移行しました

Pro Gitと入門gitでGitの復習 ブランチ編

前回までのあらすじ

今回はローカルブランチから。

参考

他のVCSとの違い

  • Subversionなどは各ファイルに対しての差分を時間軸で持っていた
  • Gitではコミットのたびにその時のリポジトリ全体のスナップショットをとる
    • ただし、変更がなかったファイルは以前のスナップショットで格納したファイルへのリンクを貼っている

Gitのオブジェクト

Gitには大きく分けて4つのオブジェクトが存在する。

  • Commitオブジェクト
  • Treeオブジェクト
  • Blobオブジェクト
  • Tagオブジェクト
Commitオブジェクト

リポジトリのルート。ファイル情報(ツリー)やメタデータを格納している。以下のコミットのCommitオブジェクトを見てみる。

$ git log --pretty=oneline
5f431a8cf6023e7398102dfef8b88baf1c581023 Typo 4

log --pretty=rawコマンドを実行するとハッシュタグがいろいろと。

$ git log --pretty=raw 5f431a8cf6023e7398102dfef8b88baf1c581023
commit 5f431a8cf6023e7398102dfef8b88baf1c581023
tree de445cf5b526c554dea465d09cea6d65059d1f80
parent a59ff99de68cbf359c814f25cda9c926ef9cdad9
author kk_Ataka <test@example.com> 1329818747 +0900
committer kk_Ataka <test@example.com> 1329819044 +0900

    Typo 4
commit このコミットに対するSHA1
tree このコミットの中身を記載しているSHA1
parent 一つ前のコミットのSHA1名。存在しない場合はそれが一発目(Rootコミット)、マージされた場合は1つ以上になる場合もある
author 作成者
committer コミッター

author, committerあたりがメタデータになるのかな。

Treeオブジェクト

あるコミット時点の中身を格納している。ls-treeコマンドかshowコマンドで確認が出来る。ls-treeコマンドの方が詳しい。

$ git ls-tree 5f431a8cf6023e7398102dfef8b88baf1c581023
100644 blob 27f338f5bd0c368f96e063127705bd1bb81e992a    README # ファイル
100644 blob 0dc64072619bf0734c878d90e9150b6978898083    index.html # ファイル
100644 blob 543200914423ddc0cb2249c322f262e31ee11c55    menu.html # ファイル
100644 blob c447b5cfd585f44aafef7d513c5efea5471e2848    convert.rb # ファイル
040000 tree a1117a81580de591d292b9e6d80deee3e1cabd85    testdata # ディレクトリ

#testdataディレクトリを調査
$ git ls-tree a1117a81580de591d292b9e6d80deee3e1cabd85
040000 tree a9da0b188817cc119eff96f4c8db5306d0be009d    init # ディレクトリ

#initディレクトリを調査
$ git ls-tree a9da0b188817cc119eff96f4c8db5306d0be009d
100644 blob 2918a6642d19aadf2b11213978ae6044166a87e0    read_cell # ファイル

showで調査する場合はこんな感じ。ファイル名だけ?

#initディレクトリを調査
$ git show a9da0b188817cc119eff96f4c8db5306d0be009d
tree a9da0b188817cc119eff96f4c8db5306d0be009d

read_cell

実行権、ファイルタイプ、SHA1名、ファイル名が出力される。ファイルタイプは超ざっくりこんな感じみたい。

blob 普通のファイル
tree ディレクトリ
Blobオブジェクト

ファイルそのもの。showコマンドで見る事が出来るのはファイルの中身。

#READMEを調査
$ git show 27f338f5bd0c368f96e063127705bd1bb81e992a
Hello Wrld
#index.htmlを調査
$ git show 0dc64072619bf0734c878d90e9150b6978898083
<html>
  <head>
    <title>Welcome</title>
  </head>
  <body>
    <h1>Hello</h1>
    <p>Hello world !!</p>
  </body>
</html>
#menu.htmlを調査
$ git show 543200914423ddc0cb2249c322f262e31ee11c55
<html>
  <head>
  </head>
  <body>
    <h1>menu</h1>
  </body>
</html>

で、ブランチ

ブランチはこの一つのCommitオブジェクトをさすポインタとなる。今は最新がこれ。

$ git log --pretty=raw 5f431a8cf6023e7398102dfef8b88baf1c581023
commit 5f431a8cf6023e7398102dfef8b88baf1c581023
tree de445cf5b526c554dea465d09cea6d65059d1f80
parent a59ff99de68cbf359c814f25cda9c926ef9cdad9
author kk_Ataka <test@example.com> 1329818747 +0900
committer kk_Ataka <test@example.com> 1329819044 +0900

    Typo 4

で、branchコマンドでブランチを確認すると……。

$ git branch
* master

masterというブランチがある。これは最初にコミットした時点で作られるブランチ。次にまたコミットをするとmasterブランチはそれを追いかけていく。

ブランチの作成

branch [newbranch]で作成。

$ git branch checkpoint1

branchコマンドで確認ができる。アスタリスクがついているのブランチが今のブランチ。

$ git branch
  checkpoint1
* master

ブランチの確認

基本はbranchコマンドで確認できる。

$ git branch
  checkpoint1
* master

vオプションでCommitオブジェクトのSHA1とログなどを冗長に確認できる。今は全部同じだが……。

$ git branch -v
  checkpoint1 5f431a8 Typo 4
* master      5f431a8 Typo 4

rオプションでリモートのブランチも確認できる。(まだよくわかってない)

$ git remote -v
rem1    c:/project/testRemote/remote1.git (fetch)
rem1    c:/project/testRemote/remote1.git (push)
rem2    c:\project\testRemote\remote2.git (fetch)
rem2    c:\project\testRemote\remote2.git (push)

$ git branch -rv
  rem1/master 5f431a8 Typo 4
  rem2/master 5f431a8 Typo 4

ブランチの削除

branch d [branch]、またはbranch D [branch]で削除する事ができる。

$ git branch -d checkpoint1
Deleted branch checkpoint1 (was 5f431a8).

$ git branch
* master

ちなみになうなブランチは削除できない。

$ git branch -d master
error: Cannot delete the branch 'master' which you are currently on.

dオプションとDオプションの違いは"今のブランチから到達不可能なブランチの削除を試みた場合"、警告を出す(d)か強制削除(D)か、らしい。どういうことだろう?
→parent,parentで過去へ遡及はできそうだけど、そこから未来には進めなさそう?

ブランチを切り替える

checkoutコマンドを使う。

$ git branch checkpoint1

$ git checkout checkpoint1
Switched to branch 'checkpoint1'

$ git branch
* checkpoint1
  master

ブランチを作りつつcheckoutも同時に行う事もできるcheckout -b [newbranch] [branch]

$ git checkout -b check-b master
Switched to a new branch 'check-b'

$ git branch
* check-b
  checkpoint1
  master

ただし、作業ディレクトリにファイル作りっぱなしとかステージングしっぱなしの状態だと原則としてブランチの切り替えはできない。

$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
        index.html
Please, commit your changes or stash them before you can switch branches.
Aborting

HEAD??

Git系のBlogエントリとか読んでるとちょいちょい出てくるHEAD。これは.gitディレクトリの中のHEADファイルに定義されていて、常に今作業中のブランチを指す、という事になっている。よく見たら前のエントリでgit reset HEAD [resetfile]というコマンドをうっていた!

$ git branch
  check-b
  checkpoint1
* master

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

masterの時はHEADもmasterだ。

$ git checkout checkpoint1
Switched to branch 'checkpoint1'

$ git branch
  check-b
* checkpoint1
  master

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

別のブランチに切り替えるとHEADも変わる。logコマンドでCommitオブジェクト(SHA1)の代わりにHEADを指定すると見れる!

$ git log --pretty=raw HEAD
commit 5f431a8cf6023e7398102dfef8b88baf1c581023
tree de445cf5b526c554dea465d09cea6d65059d1f80
parent a59ff99de68cbf359c814f25cda9c926ef9cdad9
author kk_Ataka <test@example.com> 1329818747 +0900
committer kk_Ataka <test@example.com> 1329819044 +0900

    Typo 4

commit a59ff99de68cbf359c814f25cda9c926ef9cdad9
(略)

この辺は各々のブランチの歴史を進めた上で比較しないと全部同じだからわかりづらいな。次はマージから。