たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
Gitのデフォルトブランチ名は慣習的にmaster
とされてるんだけど、これがmaster/slave(主人と奴隷)つまり奴隷制に由来する表現であるとして、2020年5月25日にミネアポリスで起きた白人警官による黒人被疑者の殺人事件を契機に盛り上がりを見せているBlack Lives Matter運動の流れを承けて、別のブランチ名に変更しようという動きがある、という事を知った。実際に、GitHubの公式のコマンドラインツールで既定のブランチ名がtrunk
に変更された(……と例に挙げたけど、たまたまタイミングが一致しただけで、このプロジェクトでの変更は事件の前だったみたい)ほか、いくつかのプロジェクトも追従しているという。
結論から先に言えば、僕もこの判断に追従した。GitHubの僕のアカウント配下のリポジトリは現時点で186あって(hub api users/piroor | jq .public_repos
で調べたらそう言われた。プルリクエスト用の一時的なforkが結構あるのでそれで多くなってる部分はあると思う)、ひとつひとつ手でやっていると埒が開かないので、それぞれローカルでは1つの作業ディレクトリにcloneされているのをいいことに、WSL1のUbuntuのbashで、GitHubのリポジトリを操作するAPIを叩けるhubを併用して以下のようなワンライナーで一気にやることにした。
export NAMESPACE=piroor;
ls | while read path;
do
[ -d "$path" -a -d "$path/.git" ] &&
echo "checking $path";
(cd "$path";
export ORIGIN_INFO="$(git remote show origin)";
(echo "$ORIGIN_INFO" | egrep "Fetch URL: git@github.com:/?$NAMESPACE/[^\\.]+\.git") &&
(export REPOSITORY="$(echo "$ORIGIN_INFO" | grep 'Fetch URL' | egrep -o "([^/\.']+)\.git" | cut -d . -f 1)";
echo "updating $NAMESPACE/$REPOSITORY";
((git branch | grep '* master' &&
(git branch --move master trunk;
git push --set-upstream origin trunk));
(hub api "repos/$NAMESPACE/$REPOSITORY" | jq .default_branch | grep master &&
hub api "repos/$NAMESPACE/$REPOSITORY" -X PATCH -F default_branch=trunk);
(URL_BASE="https://travis-ci.org/$NAMESPACE/$REPOSITORY.svg\\?branch=";
git grep -E "${URL_BASE}master" |
cut -d : -f 1 |
uniq |
xargs sed -i -r -e "s;${URL_BASE}master;${URL_BASE}trunk;g" &&
git commit -m 'Migrate master to trunk' $(git grep -E "${URL_BASE}trunk" | cut -d : -f 1 | uniq) &&
git push))));
done
まずgit remote show origin
でリモートリポジトリとの対応付けを調べる。移行対象のリポジトリであれば、git branch --move master trunk
でブランチ名を変更して、GitHub上のデフォルトブランチもtrunk
に切り替えて、Travis CIのビルドステータス画像のURLに含まれているブランチ名もついでに更新する、という感じ。他にもまだ変えないといけない所は残ってると思うけど、それは気付いた時に追々直していこうと思ってる。
同様に各リポジトリをclone済みの他の環境では、ローカルリポジトリの情報を変更するだけなので、以下のようになるか。
export NAMESPACE=piroor;
ls | while read path;
do
[ -d "$path" -a -d "$path/.git" ] &&
echo "checking $path";
(cd "$path";
export ORIGIN_INFO="$(git remote show origin)";
(echo "$ORIGIN_INFO" | egrep "Fetch URL: (https://github.com/|git@github.com:/?)$NAMESPACE/[^\\.]+\.git") &&
(export REPOSITORY="$(echo "$ORIGIN_INFO" | grep 'Fetch URL' | egrep -o "([^/\.']+)\.git" | cut -d . -f 1)";
echo "updating $NAMESPACE/$REPOSITORY";
(git branch | grep '* master' &&
(git branch --move master trunk;
git branch --set-upstream-to=origin/trunk))));
done
ローカルにcloneされてないリポジトリは、今の所まだ手つかず。hubでどうにかできるだろうとは思ってるので、やったらまた追記する。
(6月15日追記)ローカルにcloneされてないリポジトリも全部やるワンライナーは以下のような感じになった(while
ループが二重になってまでワンライナーて……)。
export NAMESPACE=piroor;
export TOTAL_REPOS=$(hub api users/piroor | jq -r .public_repos);
export PER_PAGE=100;
seq 1 $((($TOTAL_REPOS / $PER_PAGE) + 1)) | while read page;
do
hub api "users/$NAMESPACE/repos?page=$page&per_page=$PER_PAGE" |
jq -r .[].name |
while read name;
do
[ "$(hub api "repos/$NAMESPACE/$name" | jq -r .default_branch)" = "master" ] &&
echo "updating $NAMESPACE/$name" &&
(export workdir="$(mktemp -d)" &&
echo " workdir: $workdir" &&
(cd "$workdir" &&
git clone "git@github.com:$NAMESPACE/$name" --branch master --single-branch &&
cd "$name" &&
git branch --move master trunk &&
git push --set-upstream origin trunk &&
hub api "repos/$NAMESPACE/$name" -X PATCH -F default_branch=trunk);
rm -rf "$workdir");
done;
done
API叩いて直接リポジトリをリネームするやり方が分からなかった(そういうのはない?)ので、一時的にcloneして作業するという形で解決してみた。プルリク用にforkした物までゴソッとやっちゃうので、気になる人は除外処理を入れて使おう。
自分はこのように移行したけど、既存ツールチェインが壊れる危険とかいろいろあるし、これが本来意図された通りの効果がある変更だという確証もないので、みんながみんなやるべきとまでは思ってない、という事も書き添えておく。
以下、技術的な話から離れて、このような言い換えの必要性と妥当性について今回色々調べた事・考えた事を、記録のために書き残しておく。
「わかばちゃんと学ぶWeb制作の基本」のレビューを参照しながら書こうと思ったらそもそも書いてなかったので、先にそっちから書いていました。例によって自分は恐らく対象読者ではないのですが、人気の秘密を解き明かしてやんよ!とばかりに自費購入です。
本書は端的に言うと、「チームでGitを使う事になったが、よく分からないという人」「Gitをまだ使ったことがなく、なんだか難しそう……と尻込みしている人」「とりあえずなんとなくで使えてはいるが、決まった操作以外はできずにいる人」「チーム内のITエンジニアがGitを激推ししてくるのだが、使い方を覚えるのが億劫な非ITエンジニアの人」のための本だと思います。「Gitというツールの使い方の入門」+「Gitを使ったワークフローの世界への入門」という、人がGitに初めて触れる場面に即した内容になっています。
わかばちゃんシリーズの2冊目ではありますが、解説の内容は独立しています。一部キャラクターは前作からの登場のため、説明がないキャラは「誰これ?」となってしまうかもしれませんが、解説の理解を妨げるほどではなく、前作から読んでいる人のためのファンサービスと言えるでしょう。
前作同様、本書も「マンガは導入や簡単な説明で、その後のテキストが本編」という構成です。漫画要素は前作より多く、トピックによってはマンガの内容が解説として機能している部分も増えていますが、テキスト部分をすべて読み飛ばして成立する内容ではないので、基本的にはやはり漫画もテキストも全部読みましょうという事になります。
GitやGitを使ったワークフローはそれ自体がそれなりに複雑な物なので、何か基準を定めないと、解説する側も解説される側も混乱してしまうでしょう。本書は主人公の「わかばちゃん」がその基準となり、「これをしたい!」や「こういう事で困った!」という形で話題を展開していきます。まだGitを使ったことがないという段階の人が、「初心者がGitを使い始める時に起こる一通りの事」をわかばちゃんを通して疑似体験できる構成なので、予習としても苦痛を感じず通読できるのではないかと思います。
(似た分野で解説漫画を描いている自分としては、「あっ、この1コマで済ませてるやつもうちょっと2~3コマ使って段階的に説明したい……」と感じる箇所もあったのですが、これをやり過ぎるとマンガのページがどんどん膨れあがってしまうので、テキストを本文として置く限りにおいては現状はバランスの良い落とし所と言えると思います。)
本書の(ページ数的な意味での)前半はGitの基本的な使い方、後半は前半を踏まえてのケーススタディ集です。
Gitには山ほど機能があり、また、それぞれが関連しあっていることがあるため、「そういえば、あれも」「そういえば、これも」と解説し始めるとキリがありません。本書前半は「とりあえずこれだけ覚えれば使える」というレベルに持っていく事を優先して脇の話はざっくりカットしているので、多すぎる情報に惑わされることなく、押さえておかないといけない最も重要なポイントを知る事ができます。
また、そうして基本を分かった上でいざ使い始めてみて起こる様々なトラブルや「これをやりたい」といったニーズに対し、本書後半ではケースごとにその解決方法を解説しています。話題のチョイスとして、Gitの初心者~中級者が遭遇しがちな物がまとめられているため、実用性は高いです。
重要な事として、「やりたくなるけど、やっては駄目」な事は極力解説していないのも好印象です。具体的にはgit push -f
絡みの話がそれで、データ喪失などの致命的な事態に陥らないためには「それはできない」という事にしておいた方が安全なのは確かです。この点からも、本書が実際の運用の事を強く意識していることが伺えます。
自分も解説を書く立場の人間ですが、自分も含めて自分から本を書こうというような人は、自分の持つ知識を無意味にひけらかしたがるものです(偏見)。よほど自分を抑制しないと、「Gitの生まれた経緯はこれこれこうで……」というような脇の話や、使用頻度の低い使いどころの難しい機能のように判断力(判断材料となる知識)が不足している初心者には使いこなせない知識など、実際の運用上はどうでもいい情報を盛り込んでしまいがちです。
その点、本書はわかばちゃんという視点を設定することで、「ここは教えなくていい」「今は教えない方がいい」というノイジーな情報をバッサリ切り落としていて、この本を必要としている読者のための本というスタンスを貫いています。読者に寄り添う姿勢を崩さない真摯さと、嘘を書かない真摯さを保ち、その上で必要な情報をきちんと盛り込むという本書のバランス感覚は、見事だと思います。
これはターゲッティングによるものなので仕方がないのですが、基本的にSourceTreeを使っての運用の解説なので、それ以外のツールでのやり方は解説されていません。「SourceTreeを極限まで使いこなす」という観点ではなく「Gitを始めるにあたって最初の道具としてとりあえずSourceTreeを選択する」という観点での解説ですし、pushやpullといった用語はどのツールでも共通なので、本書での解説はほとんどそのまま他のクライアントに読み替えて応用できるのですが、コマンドラインツールのようにまったく操作体系の異なるクライアントの場合はそこそこ苦労しそうな気がします。
希望としては、例えば本書の説明の下にgit
コマンドや別のツールでのやり方の説明があればなお良かったのでは?とも思うのですが、それをやり始めると内容が薄いわりに分量だけあるという本になってしまいますし、第一、多すぎる情報の提示は初心者を惑わすだけですので、これらをカットしたのは至極妥当だと自分も思います。電子書籍のように、補足的な内容を視界の中にオーバーレイ(スーパーインポーズ)表示できる媒体の発展に期待したい所です。
なお、git
コマンドを使った操作に関しては、著者の湊川さんご自身の手による以下のコンテンツが存在しています。
副読本として本書と併せて読むと、SourceTreeを通した見え方以外のGitが見えてきて、よりGitへの理解が深まると思います。
<script src="https://source.pixiv.net/source/embed.js" data-id="60527082_db5d3e091bb0cd27ade787226c645edc" data-size="medium" data-border="on" charset="utf-8"></script><noscript>
シス管系女子+マンガでわかるGit コラボ特別編の裏側(想像) by Piro/結城洋志 on pixiv
</noscript>上では「課題あり」という書き方をしてしまいましたが、コマンド操作に関する説明のような、見た目に抵抗感や苦手意識を持たれそうな内容をばっさりカットしていることで、第一印象でのとっつきやすさは高く保たれていると思います。そこで考えられるのが、非ITエンジニアの人にGitを使ってもらうための入門書としての活用です。
本書の例はWebサイト制作を想定して書かれていますが、Web制作であれば企画やデザイナーといった職種の人も実作業に関わってきます。また、自分が会社の業務として過去に手がけたWEB+DB PRESSの記事執筆でも、複数人で並行して執筆して最後にとりまとめるという事をGitで行っていました。バージョン管理システムや、それを前提としたGitHubのようなサービスの便利さは、ソフトウェア開発に限らずあらゆる場面で実感できるものです。こんな便利なものをITエンジニアだけで使うに留めるのは勿体ないです。
電子化可能なデータを取り扱うプロジェクトに関わるあらゆる人の間で、データを共有しその履歴をトラッキングするインフラとして、Gitを活用する。ファイルの履歴管理や連絡の手間から皆を解放する。そのような働き方の改革にすらなり得る手引き書として、本書は広くおすすめできます。
しばらくぶりに帰宅して、さあ外出先で行った開発の結果を取ってきましょうと思ってgit pullしようとしたら、bashが起動しなくなってた。
背景を説明すると、僕は自宅ではWindowsを使ってて、Gitを使った開発にはTortoiseGitとmsysGitの組み合わせを使用しているのですが、普段は全然普通に使えてるのに今日になって急にそれが動かなくなってたという状況でした。どうもTortoiseGitが内部的に呼び出してるCygwinのbashが動いてないようで、bash単体で起動しようとしてもこんな風なエラーが出てしまってすぐにプロセスが落ちてしまいます。
0 [main] us 0 init_cheap: VirtualAlloc pointer is null, Win32 error 487 AllocationBase 0x0, BaseAddress 0x68540000, RegionSize 0x70000, State 0x10000 C:\Program Files\Git\bin\bash.exe: *** Couldn't reserve space for cygwin's heap, Win32 error 0
で、エラーメッセージを頼りに何か情報が無いかとGoogle先生に聞いてみた所、同じようなエラーが起こって困ってる人が結構いるみたいだったんですが、そこで紹介されてた以下の2つの対処法は僕の環境では効果がありませんでした。
諦めずにさらに探してたら、MSYSの謎のエラー - メモ@wantoraというエントリで紹介されてた方法でうまくいきました。
>cd "c:\program files\git\bin" >rebase -b 0x30000000 msys-1.0.dll
rebaseというのはひょっとしたら普通は入ってないかもしれません。自分はFirefoxのビルドのためにWindows SDKというのを入れてましたが、それに付いてきてたのかもしれません。リンク先のエントリによるとWindows SDK for Windows Server 2008 and .NET Framework 3.5を入れると付いてくるようです。
rebaseってなんやねん、git rebaseとは違うのか、と思って検索してみたら以下のような記事が出てきましたが、読んでもよくわかりませんでした。
SubversionからGitに移行したまとめには書いてなかったけど、TortoiseGitを使うと git@github.com:piroor/treestyletab.git とかのcloneやpullに失敗するという現象に遭遇した。「じゃあ諦めてmsysygitのbashコンソールからやるか……」で今まではなんとかなってたんだけど、これもいつの間にか動かなくなってた。「fatal: the remote end hang up unexpectedly.」とか言われる。
僕は会社でメインで使ってるUbuntuの上で作ったOpenSSHの鍵を使ってて、Windows環境ではそれをPuTTY形式の鍵に変換して使ってる。変換がうまくいってれば、OpenSSHの公開鍵をauthorized_keysに登録してあるサーバに対してもPuTTYで接続できる事を確認済み。pagent.exeが起動していてそいつにPuTTY形式の鍵が読み込まれていれば、パスフレーズの入力も省略できる。
なのにGitではうまくいかない。
TortoiseGitでSSHできない件についてはTortoiseGit 1.5.8付属のTortoisePlink.exeのバグらしい。次のリリース版では直ると書いてあるけど、今使えないんじゃ困る……なので、TortoiseGitの設定ダイアログのNetworkの所でSSH Clientに「C:\Program Files\TortoiseGit\bin\TortoisePlink.exe」の代わりに「C:\Program Files\TortoiseSVN\bin\TortoisePlink.exe」(TortoiseSVN付属のTortoisePlink.exe。こっちはこのバグがない。)を指定して回避することにした。
これでGUI(TortoiseGit)からはcloneしたりpullしたりpushしたりできるようになったんだけど、msysgitのbashからは相変わらずpullも何もできなくてやっぱり「fatal: the remote end hang up unexpectedly.」って言われる。
エラーメッセージで検索してたら、英語圏のフォーラムの記事が引っかかったんだけど、読み進めてるうちにGIT_SSHという環境変数が関係してるらしいという事が分かった。bashコンソール等でSSH経由での接続を試みる時は、Windowsの環境変数でGIT_SSHに入ってる物がSSHのクライアントとして使われるみたいだ。早速システムのプロパティで確認してみたら、大当たりだった。「C:\Program Files\TortoiseGit\bin\TortoisePlink.exe」とバグ持ちのSSHクライアントのパスが入ってたので、「C:\Program Files\TortoiseSVN\bin\TortoisePlink.exe」を指定し直しておいた。bashコンソールを起動し直してもう一度試したら、ちゃんとpullできるようになってた。
TortoiseSVNだとフォルダを複数選択してまとめてチェックアウトでワーキングコピーを最新の物に更新できてたんだけど、TortoiseGitだとそれがうまくいかないようだったので、こういうbashスクリプトで代用しようとして、Windows環境だとgitにパスが通ってない(Cygwinとmsysygit両方入ってる環境だから敢えてmsysgitにはパスを通してない)から
for dirname in *
do
if [ -d $dirname/.git ]
then
cd $dirname
echo "pull: $dirname"
"/c/Program Files/Git/bin/git.exe" pull
echo "submodule update: $dirname"
"/c/Program Files/Git/bin/git.exe" submodule update --init ""
"/c/Program Files/Git/bin/git.exe" submodule foreach 'git fetch;git c he cko ut origin/master'
cd ..
fi
done
としてたんだけど、それがうまくいかなかったからムキーッとなってたんだけど、うまくいくようになってよかった。
アドオンの開発にはずっと須藤さんに用意してもらったSubversionのリポジトリを使ってたんだけど、
と思っていて、Git(あるいは他の分散型バージョン管理システム)ならそれが解消されると期待してて、でもずっと移行できていなかった。
というのがその理由だった。でも
という事で、思い切って移行してみる事にしました。具体的な手順はSourceForge.JP のプロジェクトを Subversion から Git へ移行するに従いました。
大まかに言うとこういう事だと僕は理解してる。
ツリー型タブのSubversionリポジトリをgithub上の同名のリポジトリに移行する手順を振り返ってみる。
$ git svn clone --prefix svn/ -s https://www.cozmixng.org/repos/piro/treestyletabこれでローカルにtreestyletabという名前のディレクトリができて、これがGitリポジトリになってる。コミットを1件1件取り込むので、コミット数が多いとメチャメチャ時間がかかるけど、黙って待つ。たまに失敗するので、そういう時はできたゴミディレクトリを消してもう一度やり直す。
$ git remote add origin git@github.com:piroor/treestyletab.gitこれによって、「このリポジトリはgithubのリポジトリをcloneした物ですよ」「このリポジトリに行われた変更を元のリポジトリにpushする時は、githubにpushしますよ」ということになる。
$ git push origin masterこれで、Subversionのリポジトリから持ってきたコミット履歴が全部github上のリポジトリに反映される。
$ git branch -rこれでブランチの一覧を見れるので、
$ git checkout svn/tags/0.10.2010102501という風にしてブランチを切り替えて
$ git tag 0.10.2010102501でタグを打って
$ git push --tags originでタグの情報をgithubのリポジトリにpushする。タグの数だけこの操作を繰り返す。
$ git checkout svn/my-branchでブランチを切り替えて
$ git branch my-branchで普通のブランチとして切り直して
$ git push origin my-branch:my-branchでgithubにpushする。
自分はアドオンの数自体20個以上あるし、それぞれアホみたいに何度もリリースしててタグの数がハンパないことになってるので、全部手動でやることを考えたら気が遠くなりました。なのでこういうスクリプトをRubyで書いてみました。
#!/usr/bin/ruby
SVN_REPOSITORY_PATH = "https://www.cozmixng.org/repos/piro/<%= src_project_name %>"
GIT_REPOSITORY_PATH = "git@github.com:piroor/<%= dest_project_name %>.git"
$LOAD_PATH.unshift(File.dirname(__FILE__))
require "fileutils"
require "erb"
require "shellwords"
def main
ARGV.each do |arg|
p "process #{arg}"
args = arg.split(":")
src_project_name = args[0]
dest_project_name = args.size > 1 ? args[1] : args[0]
svn_to_git(src_project_name, dest_project_name)
end
end
def svn_to_git(src_project_name, dest_project_name)
p "svn:#{src_project_name}, git:#{dest_project_name}"
clone(src_project_name)
push(src_project_name, dest_project_name)
push_branches_and_tags(src_project_name)
rescue Exception
p $!
end
def clone(src_project_name)
result = run("git", "svn", "clone",
"--prefix", "svn/",
"-s", ERB.new(SVN_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
raise Exception.new("clone of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("Checked out HEAD:")
end
def push(src_project_name, dest_project_name)
FileUtils.cd(src_project_name) do
result = run("git", "remote", "add",
"origin", ERB.new(GIT_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
result = run("git", "push", "origin", "master")
p result.to_s
raise Exception.new("push of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("master -> master")
end
end
def push_branches_and_tags(src_project_name)
FileUtils.cd(src_project_name) do
branches = run("git", "branch", "-r")
branches = branches.to_s.split("\n")
branches.each do |branch|
next unless branch.include?("svn/")
branch.strip!
name = branch.split("svn/")[1]
next if name == "trunk"
if name.include?("tags/")
tag = branch.split("tags/")[1]
p run("git", "checkout", branch)
p run("git", "tag", tag)
p run("git", "push", "--tags", "origin")
else
p run("git", "checkout", branch)
p run("git", "branch", name)
p run("git", "push", "origin", "#{name}:#{name}")
end
end
end
end
def run(*args)
command_line = Shellwords.shelljoin(args)
result = `#{command_line} 2>&1`
result
end
main
ファイル名は svn-to-git.rb として、
$ ./svn-to-git.rb treestyletab
とやると、ここまでの手順のうちgithubのサイト上でリポジトリを作る所以外を全部自動でやってくれるという物です(ということは、スクリプトの実行前にあらかじめgithubのサイト上でリポジトリを作っておかないといけない)。これでなんとか全部のリポジトリをgithubに持ってくることができました。XUL/Migemoの辞書をSQLiteにしてみようとかそういうブランチを切ってた物が取り込めてなかったり、svn:externalsで参照してた物が入ってなかったり、Subversionに突っ込んでから1回もコミットしてないプロジェクトをまだgithubに持ってきてなかったり(必要あるの? 無いよね?)という課題は残っていますが。→ブランチの取り込み方が分かったので追記しました。→svn:externalsの移行は諦めてsubmoduleにすることにしました。TortoiseGitでメニューから「Submodule Add」を選んでリポジトリにgit@github.com:piroor/makexpi.gitを、パスにbuildscriptを指定する、という手順でだいたい同じような結果になるみたい。更新の時はTortoiseGitだと「Git Sync」から「Submodule Sync」しないといけないようだ。コマンドラインなら一発で更新できるようなんだけど……
今後はgit-svn駆け込み寺あたりを熟読して頑張っていきたいと思っております。あと、今後具体的にコードを提供してくれるような人がもしいれば、githubの方にpull requestっていうんですか?するようにしてもらえたら幸いです。
……というまとめエントリを書こうとしてもうちょっと調べ直してたら、git-svnでタグが自動で取り込まれないとかの問題を解消するラッパーのsvn2gitという物があるということを今更知りました。ギャフン!!!!!
……さらに後から気がついたけど、HTTPでアクセスできる公開のSubversionリポジトリをgithubに移行するだけならtagやbranchの変換も含めてgithubのWebインターフェース上の機能だけでサクッとできてしまうことが分かりました。ギャフンギャフン!!!!!!!!! 手順は以下の通りです。
最初githubのUIを英語で使ってたのと、下までスクロールしてなかったから気がついてなかった。なんということでしょう。丸1日以上を無駄にしてしまいました。
アドオンの開発にはずっと須藤さんに用意してもらったSubversionのリポジトリを使ってたんだけど、
と思っていて、Git(あるいは他の分散型バージョン管理システム)ならそれが解消されると期待してて、でもずっと移行できていなかった。
というのがその理由だった。でも
という事で、思い切って移行してみる事にしました。具体的な手順はSourceForge.JP のプロジェクトを Subversion から Git へ移行するに従いました。
大まかに言うとこういう事だと僕は理解してる。
ツリー型タブのSubversionリポジトリをgithub上の同名のリポジトリに移行する手順を振り返ってみる。
$ git svn clone --prefix svn/ -s https://www.cozmixng.org/repos/piro/treestyletabこれでローカルにtreestyletabという名前のディレクトリができて、これがGitリポジトリになってる。コミットを1件1件取り込むので、コミット数が多いとメチャメチャ時間がかかるけど、黙って待つ。たまに失敗するので、そういう時はできたゴミディレクトリを消してもう一度やり直す。
$ git remote add origin git@github.com:piroor/treestyletab.gitこれによって、「このリポジトリはgithubのリポジトリをcloneした物ですよ」「このリポジトリに行われた変更を元のリポジトリにpushする時は、githubにpushしますよ」ということになる。
$ git push origin masterこれで、Subversionのリポジトリから持ってきたコミット履歴が全部github上のリポジトリに反映される。
$ git branch -rこれでブランチの一覧を見れるので、
$ git checkout svn/tags/0.10.2010102501という風にしてブランチを切り替えて
$ git tag 0.10.2010102501でタグを打って
$ git push --tags originでタグの情報をgithubのリポジトリにpushする。タグの数だけこの操作を繰り返す。
$ git checkout svn/my-branchでブランチを切り替えて
$ git branch my-branchで普通のブランチとして切り直して
$ git push origin my-branch:my-branchでgithubにpushする。
自分はアドオンの数自体20個以上あるし、それぞれアホみたいに何度もリリースしててタグの数がハンパないことになってるので、全部手動でやることを考えたら気が遠くなりました。なのでこういうスクリプトをRubyで書いてみました。
#!/usr/bin/ruby
SVN_REPOSITORY_PATH = "https://www.cozmixng.org/repos/piro/<%= src_project_name %>"
GIT_REPOSITORY_PATH = "git@github.com:piroor/<%= dest_project_name %>.git"
$LOAD_PATH.unshift(File.dirname(__FILE__))
require "fileutils"
require "erb"
require "shellwords"
def main
ARGV.each do |arg|
p "process #{arg}"
args = arg.split(":")
src_project_name = args[0]
dest_project_name = args.size > 1 ? args[1] : args[0]
svn_to_git(src_project_name, dest_project_name)
end
end
def svn_to_git(src_project_name, dest_project_name)
p "svn:#{src_project_name}, git:#{dest_project_name}"
clone(src_project_name)
push(src_project_name, dest_project_name)
push_branches_and_tags(src_project_name)
rescue Exception
p $!
end
def clone(src_project_name)
result = run("git", "svn", "clone",
"--prefix", "svn/",
"-s", ERB.new(SVN_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
raise Exception.new("clone of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("Checked out HEAD:")
end
def push(src_project_name, dest_project_name)
FileUtils.cd(src_project_name) do
result = run("git", "remote", "add",
"origin", ERB.new(GIT_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
result = run("git", "push", "origin", "master")
p result.to_s
raise Exception.new("push of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("master -> master")
end
end
def push_branches_and_tags(src_project_name)
FileUtils.cd(src_project_name) do
branches = run("git", "branch", "-r")
branches = branches.to_s.split("\n")
branches.each do |branch|
next unless branch.include?("svn/")
branch.strip!
name = branch.split("svn/")[1]
next if name == "trunk"
if name.include?("tags/")
tag = branch.split("tags/")[1]
p run("git", "checkout", branch)
p run("git", "tag", tag)
p run("git", "push", "--tags", "origin")
else
p run("git", "checkout", branch)
p run("git", "branch", name)
p run("git", "push", "origin", "#{name}:#{name}")
end
end
end
end
def run(*args)
command_line = Shellwords.shelljoin(args)
result = `#{command_line} 2>&1`
result
end
main
ファイル名は svn-to-git.rb として、
$ ./svn-to-git.rb treestyletab
とやると、ここまでの手順のうちgithubのサイト上でリポジトリを作る所以外を全部自動でやってくれるという物です(ということは、スクリプトの実行前にあらかじめgithubのサイト上でリポジトリを作っておかないといけない)。これでなんとか全部のリポジトリをgithubに持ってくることができました。XUL/Migemoの辞書をSQLiteにしてみようとかそういうブランチを切ってた物が取り込めてなかったり、svn:externalsで参照してた物が入ってなかったり、Subversionに突っ込んでから1回もコミットしてないプロジェクトをまだgithubに持ってきてなかったり(必要あるの? 無いよね?)という課題は残っていますが。→ブランチの取り込み方が分かったので追記しました。→svn:externalsの移行は諦めてsubmoduleにすることにしました。TortoiseGitでメニューから「Submodule Add」を選んでリポジトリにgit@github.com:piroor/makexpi.gitを、パスにbuildscriptを指定する、という手順でだいたい同じような結果になるみたい。更新の時はTortoiseGitだと「Git Sync」から「Submodule Sync」しないといけないようだ。コマンドラインなら一発で更新できるようなんだけど……
今後はgit-svn駆け込み寺あたりを熟読して頑張っていきたいと思っております。あと、今後具体的にコードを提供してくれるような人がもしいれば、githubの方にpull requestっていうんですか?するようにしてもらえたら幸いです。
……というまとめエントリを書こうとしてもうちょっと調べ直してたら、git-svnでタグが自動で取り込まれないとかの問題を解消するラッパーのsvn2gitという物があるということを今更知りました。ギャフン!!!!!
……さらに後から気がついたけど、HTTPでアクセスできる公開のSubversionリポジトリをgithubに移行するだけならtagやbranchの変換も含めてgithubのWebインターフェース上の機能だけでサクッとできてしまうことが分かりました。ギャフンギャフン!!!!!!!!! 手順は以下の通りです。
最初githubのUIを英語で使ってたのと、下までスクロールしてなかったから気がついてなかった。なんということでしょう。丸1日以上を無駄にしてしまいました。
アドオンの開発にはずっと須藤さんに用意してもらったSubversionのリポジトリを使ってたんだけど、
と思っていて、Git(あるいは他の分散型バージョン管理システム)ならそれが解消されると期待してて、でもずっと移行できていなかった。
というのがその理由だった。でも
という事で、思い切って移行してみる事にしました。具体的な手順はSourceForge.JP のプロジェクトを Subversion から Git へ移行するに従いました。
大まかに言うとこういう事だと僕は理解してる。
ツリー型タブのSubversionリポジトリをgithub上の同名のリポジトリに移行する手順を振り返ってみる。
$ git svn clone --prefix svn/ -s https://www.cozmixng.org/repos/piro/treestyletabこれでローカルにtreestyletabという名前のディレクトリができて、これがGitリポジトリになってる。コミットを1件1件取り込むので、コミット数が多いとメチャメチャ時間がかかるけど、黙って待つ。たまに失敗するので、そういう時はできたゴミディレクトリを消してもう一度やり直す。
$ git remote add origin git@github.com:piroor/treestyletab.gitこれによって、「このリポジトリはgithubのリポジトリをcloneした物ですよ」「このリポジトリに行われた変更を元のリポジトリにpushする時は、githubにpushしますよ」ということになる。
$ git push origin masterこれで、Subversionのリポジトリから持ってきたコミット履歴が全部github上のリポジトリに反映される。
$ git branch -rこれでブランチの一覧を見れるので、
$ git checkout svn/tags/0.10.2010102501という風にしてブランチを切り替えて
$ git tag 0.10.2010102501でタグを打って
$ git push --tags originでタグの情報をgithubのリポジトリにpushする。タグの数だけこの操作を繰り返す。
$ git checkout svn/my-branchでブランチを切り替えて
$ git branch my-branchで普通のブランチとして切り直して
$ git push origin my-branch:my-branchでgithubにpushする。
自分はアドオンの数自体20個以上あるし、それぞれアホみたいに何度もリリースしててタグの数がハンパないことになってるので、全部手動でやることを考えたら気が遠くなりました。なのでこういうスクリプトをRubyで書いてみました。
#!/usr/bin/ruby
SVN_REPOSITORY_PATH = "https://www.cozmixng.org/repos/piro/<%= src_project_name %>"
GIT_REPOSITORY_PATH = "git@github.com:piroor/<%= dest_project_name %>.git"
$LOAD_PATH.unshift(File.dirname(__FILE__))
require "fileutils"
require "erb"
require "shellwords"
def main
ARGV.each do |arg|
p "process #{arg}"
args = arg.split(":")
src_project_name = args[0]
dest_project_name = args.size > 1 ? args[1] : args[0]
svn_to_git(src_project_name, dest_project_name)
end
end
def svn_to_git(src_project_name, dest_project_name)
p "svn:#{src_project_name}, git:#{dest_project_name}"
clone(src_project_name)
push(src_project_name, dest_project_name)
push_branches_and_tags(src_project_name)
rescue Exception
p $!
end
def clone(src_project_name)
result = run("git", "svn", "clone",
"--prefix", "svn/",
"-s", ERB.new(SVN_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
raise Exception.new("clone of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("Checked out HEAD:")
end
def push(src_project_name, dest_project_name)
FileUtils.cd(src_project_name) do
result = run("git", "remote", "add",
"origin", ERB.new(GIT_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
result = run("git", "push", "origin", "master")
p result.to_s
raise Exception.new("push of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("master -> master")
end
end
def push_branches_and_tags(src_project_name)
FileUtils.cd(src_project_name) do
branches = run("git", "branch", "-r")
branches = branches.to_s.split("\n")
branches.each do |branch|
next unless branch.include?("svn/")
branch.strip!
name = branch.split("svn/")[1]
next if name == "trunk"
if name.include?("tags/")
tag = branch.split("tags/")[1]
p run("git", "checkout", branch)
p run("git", "tag", tag)
p run("git", "push", "--tags", "origin")
else
p run("git", "checkout", branch)
p run("git", "branch", name)
p run("git", "push", "origin", "#{name}:#{name}")
end
end
end
end
def run(*args)
command_line = Shellwords.shelljoin(args)
result = `#{command_line} 2>&1`
result
end
main
ファイル名は svn-to-git.rb として、
$ ./svn-to-git.rb treestyletab
とやると、ここまでの手順のうちgithubのサイト上でリポジトリを作る所以外を全部自動でやってくれるという物です(ということは、スクリプトの実行前にあらかじめgithubのサイト上でリポジトリを作っておかないといけない)。これでなんとか全部のリポジトリをgithubに持ってくることができました。XUL/Migemoの辞書をSQLiteにしてみようとかそういうブランチを切ってた物が取り込めてなかったり、svn:externalsで参照してた物が入ってなかったり、Subversionに突っ込んでから1回もコミットしてないプロジェクトをまだgithubに持ってきてなかったり(必要あるの? 無いよね?)という課題は残っていますが。→ブランチの取り込み方が分かったので追記しました。→svn:externalsの移行は諦めてsubmoduleにすることにしました。TortoiseGitでメニューから「Submodule Add」を選んでリポジトリにgit@github.com:piroor/makexpi.gitを、パスにbuildscriptを指定する、という手順でだいたい同じような結果になるみたい。更新の時はTortoiseGitだと「Git Sync」から「Submodule Sync」しないといけないようだ。コマンドラインなら一発で更新できるようなんだけど……
今後はgit-svn駆け込み寺あたりを熟読して頑張っていきたいと思っております。あと、今後具体的にコードを提供してくれるような人がもしいれば、githubの方にpull requestっていうんですか?するようにしてもらえたら幸いです。
……というまとめエントリを書こうとしてもうちょっと調べ直してたら、git-svnでタグが自動で取り込まれないとかの問題を解消するラッパーのsvn2gitという物があるということを今更知りました。ギャフン!!!!!
……さらに後から気がついたけど、HTTPでアクセスできる公開のSubversionリポジトリをgithubに移行するだけならtagやbranchの変換も含めてgithubのWebインターフェース上の機能だけでサクッとできてしまうことが分かりました。ギャフンギャフン!!!!!!!!! 手順は以下の通りです。
最初githubのUIを英語で使ってたのと、下までスクロールしてなかったから気がついてなかった。なんということでしょう。丸1日以上を無駄にしてしまいました。
アドオンの開発にはずっと須藤さんに用意してもらったSubversionのリポジトリを使ってたんだけど、
と思っていて、Git(あるいは他の分散型バージョン管理システム)ならそれが解消されると期待してて、でもずっと移行できていなかった。
というのがその理由だった。でも
という事で、思い切って移行してみる事にしました。具体的な手順はSourceForge.JP のプロジェクトを Subversion から Git へ移行するに従いました。
大まかに言うとこういう事だと僕は理解してる。
ツリー型タブのSubversionリポジトリをgithub上の同名のリポジトリに移行する手順を振り返ってみる。
$ git svn clone --prefix svn/ -s https://www.cozmixng.org/repos/piro/treestyletabこれでローカルにtreestyletabという名前のディレクトリができて、これがGitリポジトリになってる。コミットを1件1件取り込むので、コミット数が多いとメチャメチャ時間がかかるけど、黙って待つ。たまに失敗するので、そういう時はできたゴミディレクトリを消してもう一度やり直す。
$ git remote add origin git@github.com:piroor/treestyletab.gitこれによって、「このリポジトリはgithubのリポジトリをcloneした物ですよ」「このリポジトリに行われた変更を元のリポジトリにpushする時は、githubにpushしますよ」ということになる。
$ git push origin masterこれで、Subversionのリポジトリから持ってきたコミット履歴が全部github上のリポジトリに反映される。
$ git branch -rこれでブランチの一覧を見れるので、
$ git checkout svn/tags/0.10.2010102501という風にしてブランチを切り替えて
$ git tag 0.10.2010102501でタグを打って
$ git push --tags originでタグの情報をgithubのリポジトリにpushする。タグの数だけこの操作を繰り返す。
$ git checkout svn/my-branchでブランチを切り替えて
$ git branch my-branchで普通のブランチとして切り直して
$ git push origin my-branch:my-branchでgithubにpushする。
自分はアドオンの数自体20個以上あるし、それぞれアホみたいに何度もリリースしててタグの数がハンパないことになってるので、全部手動でやることを考えたら気が遠くなりました。なのでこういうスクリプトをRubyで書いてみました。
#!/usr/bin/ruby
SVN_REPOSITORY_PATH = "https://www.cozmixng.org/repos/piro/<%= src_project_name %>"
GIT_REPOSITORY_PATH = "git@github.com:piroor/<%= dest_project_name %>.git"
$LOAD_PATH.unshift(File.dirname(__FILE__))
require "fileutils"
require "erb"
require "shellwords"
def main
ARGV.each do |arg|
p "process #{arg}"
args = arg.split(":")
src_project_name = args[0]
dest_project_name = args.size > 1 ? args[1] : args[0]
svn_to_git(src_project_name, dest_project_name)
end
end
def svn_to_git(src_project_name, dest_project_name)
p "svn:#{src_project_name}, git:#{dest_project_name}"
clone(src_project_name)
push(src_project_name, dest_project_name)
push_branches_and_tags(src_project_name)
rescue Exception
p $!
end
def clone(src_project_name)
result = run("git", "svn", "clone",
"--prefix", "svn/",
"-s", ERB.new(SVN_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
raise Exception.new("clone of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("Checked out HEAD:")
end
def push(src_project_name, dest_project_name)
FileUtils.cd(src_project_name) do
result = run("git", "remote", "add",
"origin", ERB.new(GIT_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
result = run("git", "push", "origin", "master")
p result.to_s
raise Exception.new("push of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("master -> master")
end
end
def push_branches_and_tags(src_project_name)
FileUtils.cd(src_project_name) do
branches = run("git", "branch", "-r")
branches = branches.to_s.split("\n")
branches.each do |branch|
next unless branch.include?("svn/")
branch.strip!
name = branch.split("svn/")[1]
next if name == "trunk"
if name.include?("tags/")
tag = branch.split("tags/")[1]
p run("git", "checkout", branch)
p run("git", "tag", tag)
p run("git", "push", "--tags", "origin")
else
p run("git", "checkout", branch)
p run("git", "branch", name)
p run("git", "push", "origin", "#{name}:#{name}")
end
end
end
end
def run(*args)
command_line = Shellwords.shelljoin(args)
result = `#{command_line} 2>&1`
result
end
main
ファイル名は svn-to-git.rb として、
$ ./svn-to-git.rb treestyletab
とやると、ここまでの手順のうちgithubのサイト上でリポジトリを作る所以外を全部自動でやってくれるという物です(ということは、スクリプトの実行前にあらかじめgithubのサイト上でリポジトリを作っておかないといけない)。これでなんとか全部のリポジトリをgithubに持ってくることができました。XUL/Migemoの辞書をSQLiteにしてみようとかそういうブランチを切ってた物が取り込めてなかったり、svn:externalsで参照してた物が入ってなかったり、Subversionに突っ込んでから1回もコミットしてないプロジェクトをまだgithubに持ってきてなかったり(必要あるの? 無いよね?)という課題は残っていますが。→ブランチの取り込み方が分かったので追記しました。→svn:externalsの移行は諦めてsubmoduleにすることにしました。TortoiseGitでメニューから「Submodule Add」を選んでリポジトリにgit@github.com:piroor/makexpi.gitを、パスにbuildscriptを指定する、という手順でだいたい同じような結果になるみたい。更新の時はTortoiseGitだと「Git Sync」から「Submodule Sync」しないといけないようだ。コマンドラインなら一発で更新できるようなんだけど……
今後はgit-svn駆け込み寺あたりを熟読して頑張っていきたいと思っております。あと、今後具体的にコードを提供してくれるような人がもしいれば、githubの方にpull requestっていうんですか?するようにしてもらえたら幸いです。
……というまとめエントリを書こうとしてもうちょっと調べ直してたら、git-svnでタグが自動で取り込まれないとかの問題を解消するラッパーのsvn2gitという物があるということを今更知りました。ギャフン!!!!!
……さらに後から気がついたけど、HTTPでアクセスできる公開のSubversionリポジトリをgithubに移行するだけならtagやbranchの変換も含めてgithubのWebインターフェース上の機能だけでサクッとできてしまうことが分かりました。ギャフンギャフン!!!!!!!!! 手順は以下の通りです。
最初githubのUIを英語で使ってたのと、下までスクロールしてなかったから気がついてなかった。なんということでしょう。丸1日以上を無駄にしてしまいました。
アドオンの開発にはずっと須藤さんに用意してもらったSubversionのリポジトリを使ってたんだけど、
と思っていて、Git(あるいは他の分散型バージョン管理システム)ならそれが解消されると期待してて、でもずっと移行できていなかった。
というのがその理由だった。でも
という事で、思い切って移行してみる事にしました。具体的な手順はSourceForge.JP のプロジェクトを Subversion から Git へ移行するに従いました。
大まかに言うとこういう事だと僕は理解してる。
ツリー型タブのSubversionリポジトリをgithub上の同名のリポジトリに移行する手順を振り返ってみる。
$ git svn clone --prefix svn/ -s https://www.cozmixng.org/repos/piro/treestyletabこれでローカルにtreestyletabという名前のディレクトリができて、これがGitリポジトリになってる。コミットを1件1件取り込むので、コミット数が多いとメチャメチャ時間がかかるけど、黙って待つ。たまに失敗するので、そういう時はできたゴミディレクトリを消してもう一度やり直す。
$ git remote add origin git@github.com:piroor/treestyletab.gitこれによって、「このリポジトリはgithubのリポジトリをcloneした物ですよ」「このリポジトリに行われた変更を元のリポジトリにpushする時は、githubにpushしますよ」ということになる。
$ git push origin masterこれで、Subversionのリポジトリから持ってきたコミット履歴が全部github上のリポジトリに反映される。
$ git branch -rこれでブランチの一覧を見れるので、
$ git checkout svn/tags/0.10.2010102501という風にしてブランチを切り替えて
$ git tag 0.10.2010102501でタグを打って
$ git push --tags originでタグの情報をgithubのリポジトリにpushする。タグの数だけこの操作を繰り返す。
$ git checkout svn/my-branchでブランチを切り替えて
$ git branch my-branchで普通のブランチとして切り直して
$ git push origin my-branch:my-branchでgithubにpushする。
自分はアドオンの数自体20個以上あるし、それぞれアホみたいに何度もリリースしててタグの数がハンパないことになってるので、全部手動でやることを考えたら気が遠くなりました。なのでこういうスクリプトをRubyで書いてみました。
#!/usr/bin/ruby
SVN_REPOSITORY_PATH = "https://www.cozmixng.org/repos/piro/<%= src_project_name %>"
GIT_REPOSITORY_PATH = "git@github.com:piroor/<%= dest_project_name %>.git"
$LOAD_PATH.unshift(File.dirname(__FILE__))
require "fileutils"
require "erb"
require "shellwords"
def main
ARGV.each do |arg|
p "process #{arg}"
args = arg.split(":")
src_project_name = args[0]
dest_project_name = args.size > 1 ? args[1] : args[0]
svn_to_git(src_project_name, dest_project_name)
end
end
def svn_to_git(src_project_name, dest_project_name)
p "svn:#{src_project_name}, git:#{dest_project_name}"
clone(src_project_name)
push(src_project_name, dest_project_name)
push_branches_and_tags(src_project_name)
rescue Exception
p $!
end
def clone(src_project_name)
result = run("git", "svn", "clone",
"--prefix", "svn/",
"-s", ERB.new(SVN_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
raise Exception.new("clone of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("Checked out HEAD:")
end
def push(src_project_name, dest_project_name)
FileUtils.cd(src_project_name) do
result = run("git", "remote", "add",
"origin", ERB.new(GIT_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
result = run("git", "push", "origin", "master")
p result.to_s
raise Exception.new("push of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("master -> master")
end
end
def push_branches_and_tags(src_project_name)
FileUtils.cd(src_project_name) do
branches = run("git", "branch", "-r")
branches = branches.to_s.split("\n")
branches.each do |branch|
next unless branch.include?("svn/")
branch.strip!
name = branch.split("svn/")[1]
next if name == "trunk"
if name.include?("tags/")
tag = branch.split("tags/")[1]
p run("git", "checkout", branch)
p run("git", "tag", tag)
p run("git", "push", "--tags", "origin")
else
p run("git", "checkout", branch)
p run("git", "branch", name)
p run("git", "push", "origin", "#{name}:#{name}")
end
end
end
end
def run(*args)
command_line = Shellwords.shelljoin(args)
result = `#{command_line} 2>&1`
result
end
main
ファイル名は svn-to-git.rb として、
$ ./svn-to-git.rb treestyletab
とやると、ここまでの手順のうちgithubのサイト上でリポジトリを作る所以外を全部自動でやってくれるという物です(ということは、スクリプトの実行前にあらかじめgithubのサイト上でリポジトリを作っておかないといけない)。これでなんとか全部のリポジトリをgithubに持ってくることができました。XUL/Migemoの辞書をSQLiteにしてみようとかそういうブランチを切ってた物が取り込めてなかったり、svn:externalsで参照してた物が入ってなかったり、Subversionに突っ込んでから1回もコミットしてないプロジェクトをまだgithubに持ってきてなかったり(必要あるの? 無いよね?)という課題は残っていますが。→ブランチの取り込み方が分かったので追記しました。→svn:externalsの移行は諦めてsubmoduleにすることにしました。TortoiseGitでメニューから「Submodule Add」を選んでリポジトリにgit@github.com:piroor/makexpi.gitを、パスにbuildscriptを指定する、という手順でだいたい同じような結果になるみたい。更新の時はTortoiseGitだと「Git Sync」から「Submodule Sync」しないといけないようだ。コマンドラインなら一発で更新できるようなんだけど……
今後はgit-svn駆け込み寺あたりを熟読して頑張っていきたいと思っております。あと、今後具体的にコードを提供してくれるような人がもしいれば、githubの方にpull requestっていうんですか?するようにしてもらえたら幸いです。
……というまとめエントリを書こうとしてもうちょっと調べ直してたら、git-svnでタグが自動で取り込まれないとかの問題を解消するラッパーのsvn2gitという物があるということを今更知りました。ギャフン!!!!!
……さらに後から気がついたけど、HTTPでアクセスできる公開のSubversionリポジトリをgithubに移行するだけならtagやbranchの変換も含めてgithubのWebインターフェース上の機能だけでサクッとできてしまうことが分かりました。ギャフンギャフン!!!!!!!!! 手順は以下の通りです。
最初githubのUIを英語で使ってたのと、下までスクロールしてなかったから気がついてなかった。なんということでしょう。丸1日以上を無駄にしてしまいました。
アドオンの開発にはずっと須藤さんに用意してもらったSubversionのリポジトリを使ってたんだけど、
と思っていて、Git(あるいは他の分散型バージョン管理システム)ならそれが解消されると期待してて、でもずっと移行できていなかった。
というのがその理由だった。でも
という事で、思い切って移行してみる事にしました。具体的な手順はSourceForge.JP のプロジェクトを Subversion から Git へ移行するに従いました。
大まかに言うとこういう事だと僕は理解してる。
ツリー型タブのSubversionリポジトリをgithub上の同名のリポジトリに移行する手順を振り返ってみる。
$ git svn clone --prefix svn/ -s https://www.cozmixng.org/repos/piro/treestyletabこれでローカルにtreestyletabという名前のディレクトリができて、これがGitリポジトリになってる。コミットを1件1件取り込むので、コミット数が多いとメチャメチャ時間がかかるけど、黙って待つ。たまに失敗するので、そういう時はできたゴミディレクトリを消してもう一度やり直す。
$ git remote add origin git@github.com:piroor/treestyletab.gitこれによって、「このリポジトリはgithubのリポジトリをcloneした物ですよ」「このリポジトリに行われた変更を元のリポジトリにpushする時は、githubにpushしますよ」ということになる。
$ git push origin masterこれで、Subversionのリポジトリから持ってきたコミット履歴が全部github上のリポジトリに反映される。
$ git branch -rこれでブランチの一覧を見れるので、
$ git checkout svn/tags/0.10.2010102501という風にしてブランチを切り替えて
$ git tag 0.10.2010102501でタグを打って
$ git push --tags originでタグの情報をgithubのリポジトリにpushする。タグの数だけこの操作を繰り返す。
$ git checkout svn/my-branchでブランチを切り替えて
$ git branch my-branchで普通のブランチとして切り直して
$ git push origin my-branch:my-branchでgithubにpushする。
自分はアドオンの数自体20個以上あるし、それぞれアホみたいに何度もリリースしててタグの数がハンパないことになってるので、全部手動でやることを考えたら気が遠くなりました。なのでこういうスクリプトをRubyで書いてみました。
#!/usr/bin/ruby
SVN_REPOSITORY_PATH = "https://www.cozmixng.org/repos/piro/<%= src_project_name %>"
GIT_REPOSITORY_PATH = "git@github.com:piroor/<%= dest_project_name %>.git"
$LOAD_PATH.unshift(File.dirname(__FILE__))
require "fileutils"
require "erb"
require "shellwords"
def main
ARGV.each do |arg|
p "process #{arg}"
args = arg.split(":")
src_project_name = args[0]
dest_project_name = args.size > 1 ? args[1] : args[0]
svn_to_git(src_project_name, dest_project_name)
end
end
def svn_to_git(src_project_name, dest_project_name)
p "svn:#{src_project_name}, git:#{dest_project_name}"
clone(src_project_name)
push(src_project_name, dest_project_name)
push_branches_and_tags(src_project_name)
rescue Exception
p $!
end
def clone(src_project_name)
result = run("git", "svn", "clone",
"--prefix", "svn/",
"-s", ERB.new(SVN_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
raise Exception.new("clone of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("Checked out HEAD:")
end
def push(src_project_name, dest_project_name)
FileUtils.cd(src_project_name) do
result = run("git", "remote", "add",
"origin", ERB.new(GIT_REPOSITORY_PATH).result(binding).chomp)
p result.to_s
result = run("git", "push", "origin", "master")
p result.to_s
raise Exception.new("push of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("master -> master")
end
end
def push_branches_and_tags(src_project_name)
FileUtils.cd(src_project_name) do
branches = run("git", "branch", "-r")
branches = branches.to_s.split("\n")
branches.each do |branch|
next unless branch.include?("svn/")
branch.strip!
name = branch.split("svn/")[1]
next if name == "trunk"
if name.include?("tags/")
tag = branch.split("tags/")[1]
p run("git", "checkout", branch)
p run("git", "tag", tag)
p run("git", "push", "--tags", "origin")
else
p run("git", "checkout", branch)
p run("git", "branch", name)
p run("git", "push", "origin", "#{name}:#{name}")
end
end
end
end
def run(*args)
command_line = Shellwords.shelljoin(args)
result = `#{command_line} 2>&1`
result
end
main
ファイル名は svn-to-git.rb として、
$ ./svn-to-git.rb treestyletab
とやると、ここまでの手順のうちgithubのサイト上でリポジトリを作る所以外を全部自動でやってくれるという物です(ということは、スクリプトの実行前にあらかじめgithubのサイト上でリポジトリを作っておかないといけない)。これでなんとか全部のリポジトリをgithubに持ってくることができました。XUL/Migemoの辞書をSQLiteにしてみようとかそういうブランチを切ってた物が取り込めてなかったり、svn:externalsで参照してた物が入ってなかったり、Subversionに突っ込んでから1回もコミットしてないプロジェクトをまだgithubに持ってきてなかったり(必要あるの? 無いよね?)という課題は残っていますが。→ブランチの取り込み方が分かったので追記しました。→svn:externalsの移行は諦めてsubmoduleにすることにしました。TortoiseGitでメニューから「Submodule Add」を選んでリポジトリにgit@github.com:piroor/makexpi.gitを、パスにbuildscriptを指定する、という手順でだいたい同じような結果になるみたい。更新の時はTortoiseGitだと「Git Sync」から「Submodule Sync」しないといけないようだ。コマンドラインなら一発で更新できるようなんだけど……
今後はgit-svn駆け込み寺あたりを熟読して頑張っていきたいと思っております。あと、今後具体的にコードを提供してくれるような人がもしいれば、githubの方にpull requestっていうんですか?するようにしてもらえたら幸いです。
……というまとめエントリを書こうとしてもうちょっと調べ直してたら、git-svnでタグが自動で取り込まれないとかの問題を解消するラッパーのsvn2gitという物があるということを今更知りました。ギャフン!!!!!
……さらに後から気がついたけど、HTTPでアクセスできる公開のSubversionリポジトリをgithubに移行するだけならtagやbranchの変換も含めてgithubのWebインターフェース上の機能だけでサクッとできてしまうことが分かりました。ギャフンギャフン!!!!!!!!! 手順は以下の通りです。
最初githubのUIを英語で使ってたのと、下までスクロールしてなかったから気がついてなかった。なんということでしょう。丸1日以上を無駄にしてしまいました。