Bitbucket CloudのMercurial(Hg)リポジトリをGitリポジトリに移行したときのメモ

 Bitbucket CloudのMercurial(Hg)サポート終了、そして最終的にはHgリポジトリは削除されるということで、Btibucket CloudのGitに変換・移行した手順のメモです。

bitbucket.org

 当初は、ほならサクッと変換してパパっと移行して終わり! と思っていたところ、いざHgからGitに変換・移行方法を色々調べてみると、あっ、これ存外に面倒くさいな? という感覚を得たので、移行しながら書いたメモを残しておきます。

作業環境: Windows 10 + TortoiseHG + HgGit + Convert Extension のPCで作業

 HgGitは本来Hgコマンド群でリモートのGitリポジトリを管理運用するツールですが、今回はGitリポジトリへの移行のためだけに使用します。そのため、移行したリモートGitリポジトリをHgGitで管理し続けていくという場合には本稿の手順だけでは不十分かと思います。

1. Bitbucket CloudのhgリポジトリをローカルにCloneする

 Clone完了後は失敗時のリカバリやオリジナル保全のため、ローカルでhgリポジトリを触る前に、Clone直後の状態を圧縮するなりコピーするなりしてとっておく。(HgGitの影響で何かしら操作すると.hg内にGit用ファイルが生成されたりもする)

2. コミットログのauthor名を変換(統一)する*1

 特に古いリポジトリなどでPC移行や表記ゆれなどがあり、コミット時のauthor名が統一されていないものがあった。

 移行を機にauthor名を統一することにして、Convert Extensionでリポジトリを変換を利用する。

 今回は今現在GitHubで使っているauthor名に統一した。(将来もしGitHubに持っていくとなったときに便利なので)

 author名変換リストを作成する。

 一行ごとに

[旧author名]=[新author名]

 と書いたテキストを用意する。

コミットログからauthor名を抽出する

 コマンドプロンプトで各リポジトリディレクトリに移動して、hgログ出力からauthor名表記の行を抽出する。

hg log | findstr "ユーザ:"

※hgが日本語設定になっていたので"ユーザ:"表記で抽出、英語だとおそらく"user:"

 Windows cmd標準でuniq的なコマンドが無いので*2、出力を目視確認して必要なものをauthor変換リストに記載する。

 バッチファイルを作って必要なリポジトリのhg log全部叩いたのをユニーク抽出して一発でauthor変換リストを作るやり方もあるなと思ったけれど、今回はそこまでやらなくてもいいかなという規模だったので、コンバートするリポジトリごとに実行して、適宜author変換リストに追記した。(最終的には12種あったauthor名を1つに集約)

 変換するリポジトリの一つ上のディレクトリから、author変更のリポジトリ変換を実行

hg convert --authormap [author変換ファイル] [変換元リポジトリ名] [変換後リポジトリ名]

--authorもあるが、現在は非推奨らしい

 変換後リポジトリは自動に生成されるので、フォルダなどは事前に作らず、変換元リポジトリ名-converted とした。(※指定していない場合は -hg が付いたものが生成される)

 変換後すぐは.hgしか存在していないので、updateで最新のファイル状態に復帰させて諸々確認する。

hg update

 author名が統一できておらず、author名変換の対象になったBitbucket Cloud hgリポジトリは15個中11個だった。(非公開設定のものを含む)

3. gitのbranchとしてhgのbookmarkを適宜作成する

 基本的にはhgのbranchを使って運用していたリポジトリにのみ実施する。

 hgとgitでbranchの概念や扱いが異なっており、HgGitにおいてはbookmarkがgitのbranchに対応する。

 hgリポジトリのbranchを確認

hg branches -c

※-cオプションで閉じたブランチも確認

 必要に応じてブランチに対応するブックマークを作成する。

 hgのdefaultブランチをGitのmasterブランチに対応させる場合のコマンドは以下の通り。

hg bookmark -r default master

※明示的にGitのbranch(hgのbookmark)を作らなかった場合、Pushはできるが何も見えず容量だけ消費しているGitリポジトリになることがある。今回は15個中2個のリポジトリで発生したが、上記のように明示的にmaster bookmarkを作成してから再度Pushしたところ正常に確認できるようになった。(なので、おまじないとして全リポジトリでとりあえずやっておくというのもありかもしれない)

 特に変名する必要のないブランチは -hg を付けたブックマークを作成(ブランチと同名のブックマークは作成できないため)

hg bookmark -r [ブランチ名] [ブランチ名]-hg

 作成したブックマークを確認

hg bookmarks

 最終的にブランチ移行が必要なhgリポジトリは15個中3個だった(元々ブランチを多数作っていたリポジトリ1個、hg defaultをGit masterに対応させる必要があったもの2個)。

4. Bitbucket Cloudで移行先となるgitリポジトリを作成する

 元となるBitbucket Cloud hgリポジトリ名に -git を付けたリポジトリを作成する。  public/private設定などの各種設定もhgリポジトリに準じたものとした。

 Bitbucket CloudでリポジトリのURLはリポジトリ名がそのまま利用される、リポジトリ名は後で変更が可能なので、公開リポジトリなどで同じURLを維持したい場合は元のhgリポジトリ名を -hg を付けるなどして変更した後に移行したGitリポジトリ名を元のリポジトリ名にするという手段がある。

5. 移行先のBitbucket Cloud GitリポジトリにPushする

 sshの公開鍵認証によるPushになるので、Bitbucket Cloudに公開鍵の登録と、ローカルのsshクライアントへの秘密鍵の登録を済ませておく。

 今回はTortoiseHg付属のPageantを使うので、Pageant秘密鍵を登録して、起動した状態にしておく(閉じていてもタスクトレイにいればいいはず)。

 鍵生成や登録設定については、Atlassianのサポートに記事があるので本稿では割愛する。

confluence.atlassian.com

 Bitbucket Cloud GitにPush

hg push git+ssh://git@bitbucket.org/[ユーザー名]/[Gitリポジトリ名].git

 コマンド完了後にBitbucket CloudのGitリポジトリを確認して終了。あとは置いておくなり、Gitクライアントからいじるなり、リポジトリ名変更までやって移行するなり。

 今回はGitへの移行までなので、これだけ。HgGitのまま使い続けるのであれば、毎回URI書くのは手間なので、 .hg/hgrc に各種パスを記述したりするなどいろいろな設定が必要になるはず。

移行したリポジトリ

 公開リポジトリは長年放置してあるものが多いですが、本手順での移行の参考にどうぞ。

 リポジトリ名末尾に-hgold が付いているリポジトリが移行元になったhgリポジトリです。

bitbucket.org

参考文献など

qiita.com

qiita.com

stackoverflow.com

www.proton.jp

mochi-ha.hatenablog.com

www.google.com

www.mercurial-scm.org

bokko.hatenablog.com

confluence.atlassian.com

yymm.bitbucket.io

flying-foozy.hatenablog.com

今回使わなかった移行方法など

  • Bitbucket Cloudでリポジトリ削除するときには移転先URL表示するようにできるので、同名URLにこだわれなければ何かしらで移行した別名リポジトリに飛ばすとかでいいかも(でもオリジナル消すの怖いよな...)
  • GitHub.comのimportツールで移行すると、おおむね問題なさそうだったが、コミットメッセージの日本語が化けてしまったので利用せず
  • Gitlab.comのBitbucket Cloudインポートは今のところgitリポジトリしかインポートできなかった
  • fast-exportは今回の移行方法よりも実行環境を整えるのが面倒そうだったので試さなかった

おわりに

Git移行したんやからでかいリポジトリ(TorqueLリポジトリがほぼ1GB)はGit-LFSに移行したろ! と思ったらこれまた面倒な感じだったので調査と検証中...

*1:コマンドのオプション名からauthor表記にできるだけ統一したけど、ユーザ/userの方がより正しいのかな?

*2:標準コマンドの組み合わせでuniqを実現してる例はある