LoginSignup
23
17

More than 1 year has passed since last update.

Gitリポジトリをミラーリングする

Posted at

2つの Git リポジトリ間で、コードと Wiki をミラーリングする方法を紹介します。GitLab を使って動作確認をしていますが、GitHub でも同様だろうと思います。

また、例えば GitLab には、プロジェクトを新規作成するときに別の Git リポジトリから インポートする機能 や、ずばり ミラーリングする機能 などがデフォルトで存在します。ここでは、ネットワークの問題や利用エディションの問題などで、これらの機能ではなく git コマンドだけで実現したいケースを想定しています。

確認環境

  • Git 2.30.0
  • GitLab 14.9.0-pre

リポジトリ構成

  • ミラーリング元のリポジトリ
    • https://gitlab.com/oohira/awesome-source.git
  • ミラーリング先のリポジトリ
    • GitLab で空のプロジェクトを作成しておく
    • https://gitlab.com/oohira/awesome-mirror.git

push 前に確認する
作業の性質上、間違っていないか不安になるので、git remote -v や git push --dry-run などを使って、push しようとしているミラーリング先リポジトリに間違いがないか、事前によく確認するとよいでしょう。

コードをミラーリングする方法1

後述しますが、GitLab の Merge Request や GitHub の Pull Request がない場合は、この方法が簡単です。

## 1. ミラーリング元リポジトリをローカルに取得
$ git clone --mirror https://gitlab.com/oohira/awesome-source.git awesome-mirror
$ cd awesome-mirror

## 2. push先だけミラーリング先リポジトリに差し替えて確認
$ git remote set-url --push origin https://gitlab.com/oohira/awesome-mirror.git
$ git remote -v
origin  https://gitlab.com/oohira/awesome-source.git (fetch)
origin  https://gitlab.com/oohira/awesome-mirror.git (push)

## 3. ミラーリング元リポジトリの変更をローカルに取得(初回は不要)
$ git remote update

## 4. ローカルをミラーリング先リポジトリにpush
$ git push --mirror
...
To https://gitlab.com/oohira/awesome-mirror.git
 * [new branch]      dev -> dev
 * [new branch]      main -> main
 * [new tag]         v1.0 -> v1.0
 * [new tag]         v2.0 -> v2.0

GitLab CI の注意
.gitlab-ci.yml が含まれていると、ミラーリング先でも意図せず GitLab CI がキックされてしまう可能性があります。ミラーリング先では CI/CD など使用予定のない機能は無効にしておくとよいでしょう。

保護ブランチ(タグ)の注意
GitLab や GitHub には、特定のブランチやタグを保護する機能があります(protected branches/tags)。ミラーリング先のリポジトリでこの設定が有効になっている場合、git push で上書きしようとしたタイミングで失敗する可能性があるので、その場合は保護設定を見直してください。

bare リポジトリの注意
--mirror オプションの指定によりワークツリーをもたない bare リポジトリが作成されるため、このディレクトリ内では git status など一部の Git コマンドが使えません。そのため、シェルのプロンプトに Git の情報を表示するようにしている場合は、何かコマンドを実行するたびに裏で git コマンドが実行され、fatal: this operation must be run in a work tree のメッセージが表示されることがあります。私の環境でも起きましたが、いったん無視してコマンド例からも除外しています。

Merge Request や Pull Request がある場合、GitLab や GitHub が refs/merge-requests/1 のような ref を追加で作っているようで、これを push しようとすると失敗します。無視して放っておいても実害はないのですが、気になる場合は「コードをミラーリングする方法2」をお試しください。

 ! [remote rejected] refs/merge-requests/1/head -> refs/merge-requests/1/head (deny updating a hidden ref)
 ! [remote rejected] refs/merge-requests/1/merge -> refs/merge-requests/1/merge (deny updating a hidden ref)
 ! [remote rejected] refs/merge-requests/14/head -> refs/merge-requests/14/head (deny updating a hidden ref)
 ! [remote rejected] refs/merge-requests/14/merge -> refs/merge-requests/14/merge (deny updating a hidden ref)
...
error: failed to push some refs to 'https://gitlab.com/oohira/awesome-mirror.git'

コードをミラーリングする方法2

GitLab の Merge Request や GitHub の Pull Request がある環境下でも、不要な警告を出さずにミラーリングする方法です。初回 fetch する前に fetch 対象を調整する必要があるので、手動でリポジトリをセットアップする必要があり、若干面倒です。

## 1. 空のリポジトリを作成(git clone --mirror は使わない)
$ git init --bare awesome-mirror
$ cd awesome-mirror/

## 2. fetch元にミラーリング元リポジトリを登録し、fetch対象をブランチ&タグに限定
$ git remote add --mirror=fetch origin https://gitlab.com/oohira/awesome-source.git
$ vi config
 ...
 [remote "origin"]
         url = https://gitlab.com/oohira/awesome-source.git
-        fetch = +refs/*:refs/*
+        fetch = +refs/heads/*:refs/heads/*
+        fetch = +refs/tags/*:refs/tags/*

## 3. push先にミラーリング先リポジトリを登録して確認
$ git remote set-url --push origin https://gitlab.com/oohira/awesome-mirror.git
$ git remote -v
origin  https://gitlab.com/oohira/awesome-source.git (fetch)
origin  https://gitlab.com/oohira/awesome-mirror.git (push)

## 4. ミラーリング元リポジトリの変更をローカルに取得
$ git remote update

## 5. ローカルをミラーリング先リポジトリにpush
$ git push --mirror
...
To https://gitlab.com/oohira/awesome-mirror.git
 * [new branch]      dev -> dev
 * [new branch]      main -> main
 * [new tag]         v1.0 -> v1.0
 * [new tag]         v2.0 -> v2.0

Wiki をミラーリングする方法

GitLab や GitHub では、Wiki も専用の Git リポジトリ(〜.wiki.git)で管理されているので、「コードをミラーリングする方法1」と同じ手法で Wiki のミラーリングを実現できます。リポジトリの URL を Wiki 用に変更する点だけ注意してください。

## 1. ミラーリング元リポジトリをローカルに取得
$ git clone --mirror https://gitlab.com/oohira/awesome-source.wiki.git awesome-mirror.wiki
$ cd awesome-mirror.wiki/

## 2. push先だけミラーリング先リポジトリに差し替えて確認
$ git remote set-url --push origin https://gitlab.com/oohira/awesome-mirror.wiki.git
$ git remote -v
origin  https://gitlab.com/oohira/awesome-source.wiki.git (fetch)
origin  https://gitlab.com/oohira/awesome-mirror.wiki.git (push)

## 3. ミラーリング元リポジトリの変更をローカルに取得(初回は不要)
$ git remote update

## 4. ローカルをミラーリング先リポジトリにpush
$ git push --mirror

Wiki リンクの注意
Wiki ページ間のリンクに Wiki 記法を使わず、絶対 URL で記載していると、ミラーリング先リポジトリ内でのリンクにならず、ミラーリング元と同じ URL へのリンクになってしまいます。ミラーリング先リポジトリ内で完結してリンクを機能させるためには、Wiki 記法を使った相対リンクでの記述を徹底しましょう。

補足

  • ミラーリング先リポジトリでの変更の扱い
    • やらないと思いますが、ミラーリング先のリポジトリで独自のコミットをしても、ミラーリング元の変更を再度 push するタイミングで上書きされます。ただし、force push されるので、保護ブランチが無効になっている必要があります
  • 間違ってミラーリング元に push した場合の扱い
    • 万が一、ミラーリング元のコミット履歴の方が進んでいる状態で、ローカルを誤って(ミラーリング先ではなく)ミラーリング元に push すると、ミラーリング元のコミット履歴が上書きされて先祖返りします。恐ろしいので、ここで紹介した方法は push 先が常にミラーリング先を向くようにしています(=ミラーリング元とミラーリング先で remote を分けるのではなく、1つの remote の fetch/push で分ける)
  • 細かいことを気にせずもっと簡単にミラーリングする方法
    • git clone した後で origin とは別の remote を1つ登録して push すれば、ほぼ近しいことはできます。main ブランチだけミラーリングできればよい場合などは、これで十分かもしれません
23
17
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
23
17