Help us understand the problem. What is going on with this article?

いまさらだけどSubversionからGitへ移行する(その2: プロジェクト・ディレクトリー分割)

先日、こちらの記事を書きました。

いまさらだけどSubversionからGitへ移行する

今回はその続きでSVNリポジトリー構成のバリエーションの話とGitLabなどを中心としたGitリポジトリー管理ツールとのマッピングの話になります。SVNリポジトリー上に実プロジェクトが複数含まれていた場合になります。SVN上での作業というよりも変換直後の複数実プロジェクトが混在する大きなGitリポジトリーをどうGit上で操作し分割していくかになります。

過去のSVNと最近のGitプロジェクト構成

前回の移行はこんなパターンに主に対応。

myproj
    ├─trunk
    ├─branches
    │  ├─hoge-fix
    │  └─foo-func
    └─tags
       ├─RELEASE_1_0
       └─RELEASE_2_0

これは、GitLab/GitHubみたいな Group や Subgroup, Organization や Team みたいな概念がある場合、移行先は例えば、

  • https://gitlab.example.com/mygroup/myproj.git or git@gitlab.example.com:mygroup/myproj.git

などに単純に移行することになるかと思います。

今回は、次のような形式で、GitLabの場合Group相当の部分にSVNのリポジトリーが存在し、その下にサブディレクトリーとして複数のプロジェクトが存在する場合、

myproj
    ├─trunk
    │  ├─proj-a
    │  └─proj-b
    ├─branches
    │  ├─proj-a-hoge-fix
    │  └─proj-b-foo-func
    └─tags
       ├─proj-a-RELEASE_1_0
       ├─proj-a-RELEASE_2_0
       └─proj-b-RELEASE_1_0

これを、

  • https://gitlab.example.com/mygroup/proj-a.git or git@gitlab.example.com:mygroup/proj-a.git
  • https://gitlab.example.com/mygroup/proj-b.git or git@gitlab.example.com:mygroup/proj-b.git

という形でGroup/Projectという形で分けたい場合を想定しています。

作業方法

前回の記事の作業でSVNリポジトリーが次のGitリポジトリーに既に移行できているものとします。

  • https://gitlab.example.com/mygroup/myproj.git

該当プロジェクトディレクトリーだけを抽出する

myprojproj-a ディレクトリーにcloneし、

$ git clone git@gitlab.example.com:mygroup/myproj.git proj-a
$ cd proj-a/

proj-aを抽出しそれ以外を削除

$ git filter-branch --prune-empty --subdirectory-filter proj-a master

これで、元の myproj/proj-a/* の内容が proj-a/* に抽出され他は消えます。

ブランチの抽出

$ for BRANCH_NAME in $(git branch -r | grep -e 'origin/myproj-a' | sed -e 's:origin/::');do
  git checkout "$BRANCH_NAME";
done
$ git checkout master

上記は、proj-a のブランチ名付与が proj-a-hoge-fix など proj-aで始まっているのが条件。

そうでない場合は、何が proj-a 用のSVNブランチであったかを予め確認しリストアップしたブランチ名をテキストに書いておいて、for文で回すなどするのが良いかと思われます。あるいは元のSVNリポジトリーのbranchesを確認しつつ手で、

$ git checkout hoge-fix
$ git checkout foo-func
.
.

するのも数が少なければ良いかと。

幸い、私のSVN環境ではブランチ名前を統一していたので、上記のようにfor文で回せました。

異なるプロジェクトのタグの削除

proj-a 以外の proj-b, proj-c, ... のタグが残っているので削除する必要があります。

もっと良い方法があるかもしれませんが、

$ for TAG_NAME in $(git tag -l | grep -v 'proj-b.*'); do
   git tag -d "$TAG_NAME";
done
$ for TAG_NAME in $(git tag -l | grep -v 'proj-c.*'); do
   git tag -d "$TAG_NAME";
done
.
.

こんな感じで消去。

こちらもブランチ同様に proj-a-RELEASE_1.0 など proj-aで始まる名前をルールとしてタグ付けしていたので、上記で回せました。ブランチ同様に予めタグ一覧をテキストなどにしてfor文で回したり、GitLabなどをリモートリポジトリーにするなら、タグは残したままpushし、WebGUI上からポチポチと関係ないものを削除するのもアリかもしれません。

リモートへの登録

まあ、ここらへんは普通にリモート先を変更してpushします。

$ git remote rename origin old-origin
$ git remote add origin git@gitlab.example.com:mygroup/proj-a.git
$ git push -u origin --all
$ git push -u origin --tags

繰り返し

以上を proj-b, proj-c, proj-d, ...で繰り返し、

  • https://gitlab.example.com/myproj/proj-a
  • https://gitlab.example.com/myproj/proj-b
  • https://gitlab.example.com/myproj/proj-c
  • https://gitlab.example.com/myproj/proj-d

などが移行できたら完了。

まとめ

面倒くさいですね。
SVN上でブランチ名、タグ名をある程度ルール化していたから良かったものの、そうでなかったらもっと手間がかかるはず。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away