gitのmirror便利っぽい
gitは複数のremote repositoryを扱えるが--mirror
オプションでミラーリングも行える。
レポジトリaaaaaをミラーリングして、bbbbbというレポジトリ名で運用したいときは、
$ git clone --mirror git@github.com:aaaaa/aaaaa.git
$ cd aaaaa.git/
$ git remote add --mirror=push other git@github.com:bbbbb/bbbbb.git
$ git remote update
$ git push other
便利っぽい。
github のmirrorでびっくりするところ
ただ、githubの場合はちょっとびっくりすることがあって、
プルリクエストが存在するgithubレポジトリをcloneした後、pushするとこんなwarningが出る。
$ git push other
* [new branch] hoge -> hoge
! [remote rejected] refs/pull/1/head -> refs/pull/1/head (deny updating a hidden ref)
! [remote rejected] refs/pull/1/merge -> refs/pull/1/merge (deny updating a hidden ref)
ぶっちゃけ実害はないのだが、warningは気になる。
このwarningが起きる原因は、githubがプルリクを保持するためのrefsを保持しているが、
これはreadonlyでpushするときは上書きできないからのようだ。
git-show-refすると、手元にrefsとして存在しているのがわかる。
$ git show-ref
c96b935f0f260aefae0aae4dec11adc79da948bf refs/heads/hoge
f911ddb5423cb616795f0445dd0ee82ae78d26d8 refs/heads/master
c96b935f0f260aefae0aae4dec11adc79da948bf refs/pull/1/head
9e76fd5f566430c5cd53e761a3869b4971e5b78a refs/pull/1/merge
対策
まず、git remote updateのときに取ってくるrefを限定してやればよい。
ブランチだけ取ってきたければ、以下のように設定すれば良い。
$ git remote set-branches origin 'heads/*'
すると、レポジトリのconfigはこんな感じになる。
fetchするブランチをフィルタする効果があるようだ。
[core]
....
[remote "origin"]
url = git@github.com:aaaaa/aaaaa.git
mirror = true
fetch = +refs/heads/*:refs/heads/*
[remote "other"]
....
ブランチとタグを取ってきたければ、以下のように設定すれば良い。
$ git remote set-branches origin 'heads/*' 'tags/*'
ただ、ローカルに出来てしまった、refs/pullは、これでは消えないので、
以下のコマンドで消せばよい。
git for-each-ref --format="ref=%(refname)" --shell refs/pull | \
while read entry
do
eval $entry
git update-ref -d $ref
done
再度試せば、warningが出なくなる
$ git push other
Everything up-to-date
最初から上手にやるには。
git cloneの時にオプションが指定できるので、こんな感じ。
ただし、mirrorオプションは自動でfetch=refs/*:refs/*を追記してしまうので、mirrorオプションの代わりにbareオプションを使った上で、--configオプションで自力でmirror=trueする。
$ git clone --bare --config remote.origin.fetch='+refs/heads/*:refs/heads/*' --config remote.origin.mirror=true git@github.com:aaaaa/aaaaa.git
$ cd aaaaa.git/
$ git remote add --mirror=push other git@github.com:bbbbb/bbbbb.git
$ git remote update
$ git push other
ぼやき
git cloneの--mirror
オプションは--config
にremote.origin.fetch=...
が追加されたら、--bare
と同じ挙動をしたらいいんじゃないかとおもう。
git clone --mirror --config remote.origin.fetch='+refs/heads/*:refs/heads/*' git@github.com:aaaaa/aaaaa.git
だと、
生成されるconfigは以下のようになってしまって、初回の自動fetchのときに結局refs/pullが入ってしまう。
[core]
....
[remote "origin"]
fetch = +refs/heads/*:refs/heads/*
url = git@github.com:aaaaa/aaaaa.git
fetch = +refs/*:refs/*
mirror = true
[remote "other"]
....