36
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

対githubでも、git mirrorを上手にやる

Last updated at Posted at 2017-04-12

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が出る。

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として存在しているのがわかる。

refs/pullがいる。
$ 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するブランチをフィルタする効果があるようだ。

aaaaa.git/config
[core]
        ....
[remote "origin"]
        url = git@github.com:aaaaa/aaaaa.git
        mirror = true
        fetch = +refs/heads/*:refs/heads/*
[remote "other"]
        ....

ブランチとタグを取ってきたければ、以下のように設定すれば良い。

追加設定2
$ git remote set-branches origin 'heads/*' 'tags/*'

ただ、ローカルに出来てしまった、refs/pullは、これでは消えないので、
以下のコマンドで消せばよい。

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が出なくなる

OK!
$ git push other
Everything up-to-date

最初から上手にやるには。

git cloneの時にオプションが指定できるので、こんな感じ。
ただし、mirrorオプションは自動でfetch=refs/*:refs/*を追記してしまうので、mirrorオプションの代わりにbareオプションを使った上で、--configオプションで自力でmirror=trueする。

mirroringレポジトリの作成
$ 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オプションは--configremote.origin.fetch=...が追加されたら、--bareと同じ挙動をしたらいいんじゃないかとおもう。

git clone --mirror --config remote.origin.fetch='+refs/heads/*:refs/heads/*' git@github.com:aaaaa/aaaaa.git

だと、
生成されるconfigは以下のようになってしまって、初回の自動fetchのときに結局refs/pullが入ってしまう。

aaaaa.git/config
[core]
        ....
[remote "origin"]
        fetch = +refs/heads/*:refs/heads/*
        url = git@github.com:aaaaa/aaaaa.git
        fetch = +refs/*:refs/*
        mirror = true
[remote "other"]
        ....
36
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?