git clone時のmirrorとbareの違い

みなさん、こんにちは。自称Gitが得意なまるりんです。

Gitリポジトリを移行する際は通常以下のようにやります。

$ git clone --mirror <SOURCE_REPOSITORY_URL>
$ cd <REPOSITORY>
$ git push --mirror <DESTINATION_REPOSITORY_URL>

しかしリポジトリのバックアップをmirrorではなくbareでとっている場合(git clone --bare <SOURCE_REPOSITORY_URL>)、そのリポジトリを移行してよいのか気になります。 結論として、リポジトリが保管している内容物はmirrorとbareでまったく同じなため移行しても問題ありません。 mirrorとbareはリモートリポジトリが更新された後の同期作業の点で異なります。どのような違いがあるのかを見ていきます。

mirrorについてGitの公式を参照すると次のように書かれています。

Set up a mirror of the source repository. This implies --bare. Compared to --bare, --mirror not only maps local branches of the source to local branches of the target, it maps all refs (including remote-tracking branches, notes etc.) and sets up a refspec configuration such that all these refs are overwritten by a git remote update in the target repository.

https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---mirror

mirrorはbareの意味を含んでいるが、git remote updateをしたときの挙動が違うようです。 具体的にどう違うのでしょうか。検証用リポジトリを作って確認していきたいと思います。 まず以下の3パターンでリポジトリのクローンを行います。

$ git clone git@bitbucket.org:exmedia/mirror-bare-test.git
$ git clone --mirror git@bitbucket.org:exmedia/mirror-bare-test.git mirror-test
$ git clone --bare git@bitbucket.org:exmedia/mirror-bare-test.git bare-test

次にオプションなしでクローンしたリポジトリに移動し、適当に編集し、pushします。

$ cd mirror-bare-test
$ # editする
$ git commit -a -m 'test commit'
$ git push origin HEAD

mirrorに移動して更新してみます。

$ cd mirror-test
$ git remote update
$ git log --graph --oneline
* 18d505a (HEAD -> master) test commit
* 53a6128 Initial commit

bareに移動して更新してみます。

$ cd bare-test
$ git remote update
$ git log --graph --oneline
* 53a6128 (HEAD -> master) Initial commit

mirrorはgit remote updateしたときにHEADが最新に追従しているのがわかります。 これが先ほどのmirrorの説明にある「all these refs are overwritten by a git remote update in the target repository(これらのすべてのrefsは、対象となるリポジトリのgit remote updateによって上書きされます).」の意味だと思います。