この投稿は インタープリズム的「俺達私達の進捗を上げる25個前後のTips」 Advent Calendar 2015 - Qiitaの1日目 の記事です。
こんにちは、Imamotoです。
仕事に役立つTipsの紹介ということで、今日は最近自分の開発を快適にしてくれた豆知識として、現場はSubversionだけど自分だけこっそりGitで開発しちゃう方法を紹介します。
Subversionでのバージョン管理、捗ってますか?
唐突ですが皆さん、現場でバージョン管理は捗っていますか?
バージョン管理システムはGitですか?それともSubversion(svn)でしょうか。
もしSubversionであり、尚且つSubversionであることに多少なりとも不満を感じているのであれば、
この記事はお役に立てるかもしれませんので気が向いたらご覧になってください。
Subversionのつらみ…
私はSubversionでのソースコードの管理で、以下のようなストレスを感じた経験があります。
- 並行で開発する複数の機能があるが、現場的に余程大きな改修でなければ新たなブランチを切ることができない
- コミットを分割すると分かりづらくなるので、出来るだけまとめてコミットしたい
- 呼吸をするが如し勢いで同じファイルを少しずつコミットをする人がいるので、最終的な変更点がよくわからない
- 他の人のコミットが多すぎて少し前に行った自分の開発すら追うのが難しい(自業自得)
- 開発が中途半端な状態で別作業が入る時はコミットしづらいので、仕方なく現在の状態をローカルでバックアップしなければならない(自給自足)
なんかもう色々と面倒くさいのでとにかくSubversionに関わりたくない…(自暴自棄)
このような不満を抱えながら開発するのはモチベーションにも影響しますし、
少しでも早くこのストレスを軽減すべきだと考えていました。
SubversionからGitへ
上述した悩みを解決する手段として最も手っ取り早いのはGitへの移行です。
理由は以下の通りです。
- 気軽にブランチを作れるので並行した開発が楽に行える
- 中途半端に開発した状態でもとりあえずローカルのブランチにコミットしておけば良い
- 複数のコミットをまとめたりするのも簡単に行える
なので、現場がSVNからGitに移行してくれるのが解決への一番の近道なのですが、
- そもそも現場のバージョン管理システムを選択する権限などない
- 使い慣れていない人にとっては学習コストの高さに見合うメリットを見出すのは難しい
- Gitを操作するGUIツールが結構微妙(Gitの高機能を生かしきれない)
等の理由により、現場単位でのGit移行のハードルはかなり高いと思います。
git-svnを使えば1人で気軽にGit開発ができる
そんな時に重宝するのがgit-svnです。
このツールをインストールするとgit svn
というコマンドが使えるようになります。
このコマンドが使えるようになると、以下のようなことが実現可能となります。
- Subversionのコミットログを維持したままGitリポジトリを作成できる
- ローカルで行ったGitのコミットを、Subversionのコミットとして送信できる
つまり、ローカルのGitとリモートのSubversionを紐づけて、相互にやり取りが行えるようになります。
ここまで来たらもう導入しない手は無いですよね!
以下よりgit-svnのセットアップ、運用方法、豆知識等を紹介していきます。
git-svnのセットアップ
前提
- Windows環境での作業を前提とした説明となります。
インストール
- Windows環境でGit for Windowsをインストールすると、
git svn
コマンドも標準で使えます。 - ただしSubversionでのコミット数が大量である場合は重くて初期設定時間が大変なことになるので、VM上での作業を推奨
- CentOSならば以下
$ yum install -y git-svn
Gitの初期設定
SVNとGitのユーザーマッピングファイル作成
SubversionのコミットをGitのコミットに変換する際に、以下の形式のファイルを準備するとユーザー情報を自動変換してくれます。
imamoto = imamoto <imamoto@hogefuga.higehige.example.jp> imamiya = s_imamiya <s_imamiya@hogefuga.hagehage.example.jp>
各行はSubversionのユーザ名 = Gitのユーザ名 <Gitのメールアドレス>
となっています。
このファイルは無くても問題ありませんが、その場合はメールアドレスのドメインが無関係の文字列になってしまいます。
「ファイルを手動で作るのが面倒くさい…」という場合、メールアドレスのドメインが一意という前提で以下のコマンドで過去のSubversionのコミットログからファイルを自動生成できます。
$ svn log --xml http://example.jp/svn/ | grep "<author" | sort -u | perl -pe 's/<author>(.*?)<\/author>/$1 = $1 <$1\@example.jp>/g' > ~/.svnauthors
- SubversionのURL :
http://example.jp/svn/
- ファイル名 :
~/.svnauthors
- 以下のルールでマッピング
git configの変更
- autocrlf=false : リモートからの取得・コミット時に改行コードを変更しない
- svn.authorsfile : SVNとGitのユーザーマッピングファイル指定
- これを指定すると、ユーザーマッピングファイルに無いユーザーのコミットは取り込めずにエラーとなる
- 前述の通り、指定しなくても大丈夫
- グローバル設定が嫌な人はリポジトリ毎に設定してください
$ git config --global autocrlf false $ git config --global svn.authorsfile ~/.svnauthors
Gitリポジトリの作成
- 例として以下の条件でGitリポジトリを作成する
$ mkdir ~/my_git_repo $ cd ~/my_git_repo $ git svn init -s --prefix=svn/ --username=imamoto http://example.jp/svn $ git svn fetch $ git svn show-ignore >> .git/info/exclude
git svn fetch
は途中で止まることもあるが、再開可能- SVNから取得したignore情報以外にignore対象として追加したいファイル、ディレクトリがある場合は
.git/info/exclude
に追記
既にSubversionから取得したソースで開発中の場合
- 開発ディレクトリのローカルでの変更点を確認して、残しておく必要のある変更はバックアップを取っておく
- 作成済みのGitリポジトリから
.git
ディレクトリを取得して開発ディレクトリに追加 - 開発ディレクトリから
.svn
ディレクトリを削除 - 開発ディレクトリで
git reset --hard HEAD
- バックアップしておいた変更を再び開発ディレクトリに適用
git-svnの運用
Gitディレクトリに最新のSVNコミットを取り込む
- 取り込み先はmasterブランチ
- masterブランチはSubversionのtrunkとのやり取りのみを行うようにして、開発は別のブランチを作成した方が良いと思います。
$ git checkout master $ git svn rebase
開発用ブランチに最新のSVNコミットを取り込む
- topic1, topic2 : 開発機能ごとに作られた開発用ブランチ
- masterに最新のSVNコミットを取り込んだ後、
git rebase master
でmasterブランチから差分を取り込む
$ git checkout master $ git svn rebase $ git checkout topic1 $ git rebase master $ git checkout topic2 $ git rebase master
SVNのリモートリポジトリへコミット
topic1ブランチで行った変更を、Subversionへコミットする
git checkout master
git svn rebase
でSubversionの最新コミットをmasterブランチへ取り込むgit checkout topic1
git rebase master
でmasterブランチをtopic1ブランチへ取り込むgit checkout master
git merge --no-ff --no-commit topic1
でtopic1での変更をmasterブランチへ取り込む- 取り込み内容に問題が無ければ
git commit
git svn dcommit -n
でSubversionへの送信対象のコミットを確認する- 問題が無ければ
git svn dcommit
でSubversionへ送信する
git-svnの豆知識
Subversionのディレクトリ構成が非標準的である場合
現場によっては、Subversionは/trunk
, /branches/~
, /tags/~
という標準的なディレクトリ構成ではない場合があります。
その場合はgit svn init
のオプションとして-s
をつける代わりに--trunk
や--branches
オプションで/trunk
や/branches/~
に相当するディレクトリを指定することができます。
$ git svn init --trunk=release --branches=develop/branches --prefix=svn/ --username=imamoto http://example.jp/svn
Subversionとの差分が出る場合
既にSubversionから取得したソースで開発中の場合
の項でSubversionからGitに置き換えた際に差分がある時、以下のような可能性が考えられます。
ファイルのパーミッションが変わっている
git-svnでGitリポジトリを作成すると、リポジトリのローカル設定でファイルのパーミッション変更を差分として検知するようになります。
無視しても問題ない場合はgit config core.filemode false
で解消できます。(グローバル設定ではなくローカル設定にしてください)
改行コードが変わっている
Subversionで改行コードがCRLF
になっている場合、git svn fetch
でLF
に変換されてしまう時があります。
原因は定かではありませんが、どうやら以下のようなパターンだとこの現象が起きてしまうようです。
(1) 今まで存在しなかったディレクトリ内の新規ファイル(改行コードCRLF)をSubversionにコミットする (2) Gitリポジトリに変換する (3) 対象ファイルがLFに変換されている
こちらの事象は解決策が見つかりませんでした。。
知ってる方がいたら教えていただけると幸いです。
複数人でGitで開発したい場合
個人ではなく、少人数のチームでGitで開発したい場合はgitのremote情報を設定すればリモートリポジトリへpushできます。
$ git remote add origin git@github.com:user/repo_name.git $ git push -u origin master
ただしSubversionからの取得、Subversionへのコミットを行えるのはSVNからGitリポジトリを作成したオーナーのみです。
複数人で共有する場合、オーナー以外は単なるGitリポジトリとして使うことになります。
また、Subversionとの紐づけが壊れる為、masterブランチへの直接push等は行わない等のルールを設定する必要もあります。
おわりに
今回git-svnを個人でこっそり使うというテーマで記事を書かせていただきました。
このテーマを選んだ動機は「私自身の開発が楽になった」というのが一番大きいのですが、
その他に「個人でgit-svnを使う」という趣旨の情報がネット上に少なかったということが挙げられます。
git-svnは本来、SubversionからGitへ移行する目的で使用されることがほとんどですので、この記事はGitを使いたくても使えない、移行したくてもできない、そんな環境の方の参考になれば幸いです。
参考にさせていただいたサイトは数えきれないほどあり列挙しきれないのですが、特に参考にさせていただいたスライドを1つご紹介いたします。
git-svnで始めるボッチのためのGit // Speaker Deck
最後まで読んでいただきありがとうございました。
インタープリズム的「俺達私達の進捗を上げる25個前後のTips」 Advent Calendar 2015 - Qiitaの2日目の記事