gitのcommitについて調べてみた

こんばんは。 かまいたちがコント優勝しましたね! かまちたちが昔やってた伏せさせて手をあげる奴めっちゃ好きです。 あらびき団懐かしい、、、

Git

gitを使っているもののよく分からないことが多かったんですよね。 HEAD ってなんだろとか、gitってそもそもなんなんだろ、生きてるってなんだろ、みたいな。 そんな時、後輩からプレゼントという言葉とともにこのリンクが送られてきました。 Gitのコミットの裏側で起こっていること この記事がとても面白かったので、この記事を元にいろいろコミットに関わることをまとめてみました!

コミットについて

  • コミット情報の中には、5つの情報が入っている。
    1. 「コミット時のファイルの状態」の情報 = インデックス(staging area)にあった情報
    2. 「親コミットはどれか」という情報 親 - 現在選択しているコミット 子 - 新たにコミットしたことで作成されたコミットオブジェクト
    3. 作成者
    4. コミット者
    5. コミットメッセージ
  • 親子のコミット情報を比べることで「2つのコミット間の差分」を知ることができる。
  • ただし、最初のコミットはルートコミットと呼ばれ、親コミットの情報の代わりに、 以前は何もない状態であったことが記録される。
// 最新のコミット情報を表示
$git cat-file -p HEAD
tree 80f6c9625d2da5708724f2fd12db101e43ddfe4d                 -> 1
parent 8d5e087b279d9d2003e532e78078eae14d05ff2b               -> 2
author nekootoko3 <nekootoko3@gmail.com> 1508682946 +0900     -> 3
committer nekootoko3 <nekootoko3@gmail.com> 1508682946 +0900  -> 4

neko ni kansuru commit wo shitazo-!                           -> 5


// 最初のコミットの場合
// parent がない!!
tree 08585692ce06452da6f82ae66b90d98b55536fca
author nekootoko3 <nekootoko3@gmail.com> 1508683149 +0900
committer nekootoko3 <nekootoko3@gmail.com> 1508683149 +0900

first commit dayo

1 の コミット時のファイルの状態については Gitのコミットの裏側で起こっていること こちらに詳しく載っておりましたが、今回割愛してます。

ブランチについて

  • ブランチは特定のコミットオブジェクトを指し示すもの

HEADとは

  • 特殊なブランチで「選択中のブランチ」を指し示す
    • HEADが指し示すbranch = 今いるbranch
  • なので、HEADとブランチとコミットオブジェクトはこのような関係になっている。
    • HEAD -> ブランチ -> コミットオブジェクト
  • git branch あるいは .git/HEADを見ることで、 現在のブランチ (HEAD) を確認できる。

    HEAD -> ブランチ -> コミットオブジェクト の関係を確認。

// HEADの位置を確認
$ git branch
* master
neko
$ cat .git/HEAD
ref: refs/heads/master

-> masterブランチが選択されていて、
   masterブランチはどうやら refs/heads/master にあるらしい

// ブランチの内容を確認
$ cat .git/refs/heads/master
9dd7cd67a1e8ce67e68b8e73fd162db78dce5b3e -> コミットオブジェクトようだ

// ブランチの中身を確認
$ git cat-file -p 9dd7cd67a1e8ce67e68b8e73fd162db78dce5b3e
tree 80f6c9625d2da5708724f2fd12db101e43ddfe4d
parent 8d5e087b279d9d2003e532e78078eae14d05ff2b
author nekootoko3 <nekootoko3@gmail.com> 1508682946 +0900
committer nekootoko3 <nekootoko3@gmail.com> 1508682946 +0900

neko ni kansuru commit wo shitazo-!

checkoutについて

  • git checkoutすると、2つのことが行われる。
    1. HEADを指定したブランチに切り替える。
    2. 作業ディレクトリの内容を、そのブランチが指し示すコミットの状態に復元する。

mergeとrebaseについて

  • マージすると、マージコミットという特殊なコミットが行われる。
    • コミットオブジェクトが持つ情報もコミット時と少し異なる。
      1. 親コミットはマージしたブランチ2つになる。
      2. 「コミット時のファイルの状態」は、2つの親が持っていた情報を合わせたものになる。
// マージしたコミット情報を出力
$git cat-file -p 8d5e087b279d9d2003e532e78078eae14d05ff2b
tree 217f98d1f04a427cb1736ebe7e984ec71fb6f4ad
parent 7b0c7594c52290df009b3fbe6ffe4bf144e46934 -> parentが2つになった!
parent fe656e3cd007b35cc492d879db944eb0494518e0 -/
author nekootoko3 <nekootoko3@gmail.com> 1508679080 +0900
committer nekootoko3 <nekootoko3@gmail.com> 1508679080 +0900

Merge branch 'neko'
  • rebaseした時に行われる処理
    • そもそもrebaseとは?gitのgraphを先に見よう。
// これが元のgraph
* コミット4  (HEAD, master) Merge branch '修正2のブランチ'
|\
|  * コミット3 修正2
|/
| * コミット2  (開発ブランチ) 修正1
|/
* コミット1

// git merge 開発ブランチするとこうなる
* コミット5 (HEAD, master) Merge branch '開発ブランチ'
| \
*  | コミット4  (HEAD, master) Merge branch '修正2のブランチ'
|\  \
|  * | コミット3 修正2
|/  /
| * コミット2  (開発ブランチ) 修正1
|/
* コミット1

// git checkout 開発ブランチ
// git rebase master するとこうなる
* コミット2  (HEAD, 開発ブランチ) 修正1
* コミット4  (master) Merge branch '修正2のブランチ'
|\
|  * コミット3 修正2
|/
* コミット1
  • rebaseであたかもmasterの最新コミットから、修正ブランチを切ったかのようにできる。
    • ここで行なっている処理は次の流れ。
      1. 開発ブランチの各コミットで「どのような変更を行なったか」を記憶する。
      2. masterにcheckoutする
      3. そこから新しく開発ブランチを切る
      4. 記憶しておいた「どのような変更を行なったか」を適用し直していく
    • 4の処理を行なっている際にはconflictが起きる可能性もある その場合にはconflictを修正して、git rebase --continue
      • やっぱやーめたって時には git rebase --abort

おわり

ということで、今回はgitについて書いてみました。 何事も深く理解するのは楽しいものですね!

参考リンク

git pull と git pull –rebase の違いって?図を交えて説明します!
Git をはじめからていねいに