graftedなgitコミットとは何者か・・・
前回の記事にちょっと出てきたのですが、gitのコミットログを見た時にハッシュ値の横にgrafted
というものを初めて見たので調べてみました。
ここに至る経緯
ざっくりまとめると
- Homebrewで1つ前のバージョンのものをインストールしたかった
brew switch
が出来なかったのでgit checkout
でFormulaを古いバージョンに戻そうとした- 該当ファイルの
git log
を見たらコミット履歴が1つしかなくて戻せなかった - そのコミットのハッシュ値の隣に
(grafted)
の表記があった
という感じ。
ググってみた
率直にgit grafted
をキーワードでググって幾つか記事を見てみます。
タイトルの「shallow clone した際の "grafted" なコミットとは一体何ですか?」のコレ感がパない\(^o^)/
このStackOverflowの質問の要約は
- gitで
--depth
オプションを使ってshallow cloneするとgrafted
マークが付く - ググっても納得行く情報が見つからなかった
git grafts
とは違いそうだけど同じ意味をするもの?- コミット履歴を省略しているフラグに過ぎないのか?それとももっと特別な意味がある?
という感じですかね。
ここでわかったのは
git clone --depth
するとgrafted
マークが付く- その他にも
grafts
という概念がgitにはある
ということです。
StackOverflowの回答でも触れられていましたけど、上記の記事の質問に以下のページへのリンクがありました。
超絶ざっくりまとめると
- 異なる開発ラインを結合することが出来る
- 別のSCMからインポートした場合など別リポジトリとの履歴と結合するのに便利
- Git 1.6.5で追加された
git replace
でこれが出来る
ということですかね。なんか間違っていそうですが。。
試してみる
git clone --depth
近々試そうとしているdeployer
を使わせてもらって試してみます。
普通にgit clone
してみます。
$ git clone git@github.com:deployphp/deployer.git Cloning into 'deployer'... remote: Counting objects: 8810, done. remote: Compressing objects: 100% (5/5), done. remote: Total 8810 (delta 0), reused 0 (delta 0), pack-reused 8805 Receiving objects: 100% (8810/8810), 1.85 MiB | 578.00 KiB/s, done. Resolving deltas: 100% (5649/5649), done. $ cd deployer $ git log --graph * commit 006e0b16f3a92025759fc1da30481000e00c0320 (HEAD -> master, origin/master, origin/HEAD) | Author: Martin Supiot <martin@webaaz.com> | Date: Tue Apr 10 09:49:32 2018 +0200 | | fix typo (#1585) | * commit 35027de18ba2eadd6205336961910f0f400e557c | Author: Keith Bremner <kmbremner@gmail.com> | Date: Sat Mar 17 17:39:37 2018 +0000 | | Update shared.php (#1571) | | fix typos | :
ついでに.git
ディレクトリ配下を確認してみます。
$ ls .git HEAD description index logs packed-refs config hooks info objects refs
ふむ。
では次はgit clone --depth=1
をしてみます。
$ git clone --depth=1 git@github.com:deployphp/deployer.git Cloning into 'deployer'... remote: Counting objects: 218, done. remote: Compressing objects: 100% (199/199), done. remote: Total 218 (delta 36), reused 50 (delta 4), pack-reused 0 Receiving objects: 100% (218/218), 119.99 KiB | 8.57 MiB/s, done. Resolving deltas: 100% (36/36), done. $ git log --graph * commit 006e0b16f3a92025759fc1da30481000e00c0320 (grafted, HEAD -> master, origin/master, origin/HEAD) Author: Martin Supiot <martin@webaaz.com> Date: Tue Apr 10 09:49:32 2018 +0200 fix typo (#1585)
--depth=1
とオプションを指定したのでログにはコミットが1つだけとなりHEAD
にgrafted
がつきました。
そして普通にclone
した場合と比較してオブジェクト数が1/40まで減っています!!
先程と同様に.git
配下も確認してみます。
$ ls .git HEAD description index logs packed-refs shallow config hooks info objects refs
直下にshallow
というファイルが増えましたね。
中身を確認してみます。
$ cat .git/shallow 006e0b16f3a92025759fc1da30481000e00c0320
grafted
なポジションのコミットのハッシュ値が記録されているようです。
ローカルのHomebrewのコアリポジトリhomebrew-core
を確認してみたら同じようになっていました。
あまり意識して--depth
オプションをつけることがないですが、
大規模なリポジトリを扱う際(かつ過去を振り返らない場合)は有効なオプションですね。
git replace --graft
正直、今回のことがなければgit replace
を使うことはなかったかなと。。
初めて見たのでマニュアルを確認して先程と同様にdeployer
リポジトリを使って叩いてみます。
Git - git-replace Documentation
$ git log --graph * commit 006e0b16f3a92025759fc1da30481000e00c0320 (HEAD -> master, origin/master, origin/HEAD) | Author: Martin Supiot <martin@webaaz.com> | Date: Tue Apr 10 09:49:32 2018 +0200 | | fix typo (#1585) | * commit 35027de18ba2eadd6205336961910f0f400e557c | Author: Keith Bremner <kmbremner@gmail.com> | Date: Sat Mar 17 17:39:37 2018 +0000 | | Update shared.php (#1571) | | fix typos | :
コマンドがgit replace --graft {commit}
となるのでHEAD
を指定してみます。
$ git replace --graft HEAD $ git log * commit 006e0b16f3a92025759fc1da30481000e00c0320 (HEAD -> master, replaced, origin/master, origin/HEAD) Author: Martin Supiot <martin@webaaz.com> Date: Tue Apr 10 09:49:32 2018 +0200 fix typo (#1585)
今度はgrafted
ではなくreplaced
とマークされましたね。
マニュアルにAdds a replace reference in refs/replace/ namespace.
と記載があったので確認してみます。
$ ls .git HEAD description index logs packed-refs config hooks info objects refs $ ls .git/refs/replace/ 006e0b16f3a92025759fc1da30481000e00c0320
git clone --depth
の時と違って.git/shallow
ではなく.git/refs/replace/{commit}
が作成されていました。
まとめ
正直ちょっとよくわからずw
grafted
のマークはclone
する時点で対象のオブジェクトが絞られているのでリポジトリ容量はだいぶ軽くなるので、
別リポジトリを参照のためにネストする場合は最新のコミットだけ知っておけば事足りるので活用出来る気がしますがreplaced
の使いみちがピンと来ず。。
業務でgitを使っている間にgrafted
やreplaced
なリポジトリを作ることはなさそうだなーというのが正直なところ。
最近ポッドキャストのsoussune
を一ヶ月遅れで聴いていてその中でgitの話があったのですが、内部構造とかもっと詳しくなるとこの辺ピンとくるのかな。
入門Git買って読むかー(´•ω•`)
- 作者: 濱野純(Junio C Hamano)
- 出版社/メーカー: 秀和システム
- 発売日: 2009/09/24
- メディア: 単行本
- 購入: 31人 クリック: 736回
- この商品を含むブログ (155件) を見る
またわかったら別記事として書こうと思います。眠いので寝るー(ヽ´ω`)
追記
寝ぼけててまとめの文章が超絶おかしいけど、git clone --depth
自体はわりと普通にやる行為なんですよね。
ただその際にgrafted
とマークが付くことを初めて知ったのとそこがイマイチしっくり来ていません。故にわからず。。
graft
を直訳すると接ぎ木
という意味なので別リポジトリとジョイントする際にそちら側の履歴を知っておく必要はないのでgrafted
になるのかなと思うのですが、
その辺のGitの運用フローがピンときていないのでclone --depth
とreplace --graft
がふわっとしている感じなのかな。
もう少し調べてわかったら纏めたいと思います。