事象発生日:2019-04-26
記事公開日:2019-04-26
アクセス数:62569
TortoiseSVNでのバージョン管理システムApache Subversion (SVN) の必要最低限の使い方と,わりと便利な機能について,まとめておきます.
純粋なソフトウェア開発ではなく,ハードウェアに書き込んで動作させるようなコードを若干想定していたりします.
紆余曲折あり,研究室で,SVNとコーディングについてのもろもろの簡易講習会を開催することになってしまいました.
こういったものを公開するのには,いくつかの理由がありますが,一番は,
よく2ちゃんねるで寿司屋の蛇口が手を洗う場所と言って憚らない人がいる.
指導教員が昔からそこで手を洗う人で,学生にもそこで手を洗うと教える.
みんなで寿司屋へ行くと「熱い! 熱い!」とか言いながら大真面目に手を洗っているのである.
不幸なことにその寿司屋は個室だから誰も注意してくれない.
などで端的に表現されているよう(※ 引用元での文脈はコーディングについての話ではない)に,その集団でのスタンダードが世間一般のスタンダードから乖離してしまう,ということが起きやすいと考えているからです.
僕自身も数十人規模以上の大規模開発などしたことはありませんし,研究室と家以外でSVNは使わないので,もしかしたら(というか,少なからず)世間一般との乖離があるかもしれません.
(ので,なにかあったらご指摘お願いします!)
とまあ,言い訳が長くなりましたが,本題に移りましょうか...
Microsoft Windows 10 Home 1809 (64bit)
TortoiseSVN - A Subversion client for Windows Version 1.9
TortoiseSVNは適当にインストールしてください.自動的にSVN本体も入ります.
1点注意しなければいけないことは,日本語化はしないほうが良い,ということ.
日本語訳にいくつかの間違えを発見しており(2017年当時),例えば,MergeのFromとToが逆になっているなど致命的なものもあるので,英語のままをおすすめします.
バージョン管理の必要性を簡単にいうと,
一応の成功(編集可能)_intに直した.c
みたいなファイル名を撲滅するため.
(このファイル名は,去年の弊研究室新人研修でいつの間にかに爆誕してたものです....)
新人研修くらいの一つのファイルに収まるコードならファイル名は重要ではないけれど,複数に分割している場合などは容易に変更できませんし,
簡単に過去版にロールバックさせたり,変更履歴を残したり,デプロイ環境を整備したり,複数人で並列に開発したり,,,と考えれば,バージョン管理の重要性は理解できるはずです.
そのバージョン管理のなかの,ソースコードなどに特化したものの1つが,このSVNです.
最近だと,Gitのほうが流行っている気がしますが,個人的には,SVNのほうが中央集権的なので,研究室くらいのプロジェクトには向いているのかなぁ,などと思ったりもしています.
ただ,Pull Request(これは,Gitのネイティブな機能ではなく,GitHubの機能ですが)だけは,SVNにも欲しい,とつくづく思います.
なお,ソースコードに限らず,例えばデザイン素材にも,Abstractなどに代表されるバージョン管理システムがあったりします(最近知った)し,
Google DriveやDropbox,というかWindowsネイティブにもバージョン管理機能は備わっています.
バージョン管理,大事!
(一応,バージョン管理とバックアップはまた別の問題,ということも記しておきます.)
雑に,概要図を下図にまとめました.
用語説明をすると,
Repository | すべてのデータ(各バージョンの情報や,コミットログ(後述)など)が保存されている.通常は開発メンバがアクセスできるサーバーなどに設置させる. (SVNの開発元はApacheなので,Apache HTTP Serverとの相性はよく,研究室にサーバーを立てるときもさくさくいけた.) | ||
Trunk | メインのソースコード保管場所.各々が実装したコードは最終的にはここに集約される. | ||
Branch | Trunkに影響を与えずに開発を行う場所.これもRepositoryに含まれるため,バージョン管理される. | ||
Working Copy | 実際の作業場.これは開発者のPC内に設置され,実際にここにあるファイルを編集することになる. |
といったところ.
下図において,Bさんになったつもりで簡単な作業フローを追うと,
Aさんに迷惑をかけないように,現在の最新安定動作版 (Trunk) からBranch (Branch 1) を生成する. | |
生成したBranch 1を自分のPC (Working Copy) に落としてくる.(Working Copyがまっさらの場合,Checkoutするといい,すでに作業中の場合はSwichするという.) | |
開発が一段落したら,変更をRepositoryにあるBranch 1に保存 (Commit) する.これを適当に繰り返す. | |
Branch 1で開発した機能が完成し,試験も終わってTrunkに組み込んでも問題ない,となったら,TrunkにSwitchし(Working CopyをTrunkに切り替え),そこにBranch 1の内容を統合させる (Merge). これは,基本的には自動的に行われるという,素晴らしい仕組みになっている. TrunkとBranch 1がMergeされたソースコードでの簡易試験や差分チェック (Diff) をし,問題なければこれをTrunkへCommitする. ここで初めて,Bさんの開発内容がTrunkへと反映される. (注意すべきところは,MergeはWorking Copyで行われる,ということ.Mergeはバージョン管理においてもっともトラブルの発生するところだが,誰にも影響しない,CommitしないかぎりログにものこらないWorking Copyなので,まあ恐れず適当に試してみればいいと思う.) | |
同様にして,また新しいBranch 2を作って作業を繰り返しても良いし,Branch 1に追加で実装を加えていって,またMerge後にTrunkへCommitしていっても構わない. また,不要になったBranchは目に見えるところにあると邪魔なので削除する.もちろん,任意のバージョンへロールバックできるため,“消す”,といのは見えなくなるだけであり,簡単に復元可能である. |
というような感じになります.
上の流れからわかるように,Working Copyを除くすべてのデータはRepositoryにあるので,例えば研究室PCでBranch AにCommitし,帰宅後,自宅PCにBranch AにCheckout/Switch/(Update)し,続きの作業を行う,なんてことも可能です.
また,1つのBranchを複数人でいじることも可能です.
簡単に,Gitについても触れておきます.
中央集権的なSVNの場合,ファイル編集→Commit,で終わり(Repositoryにデータが保存される)でした.
Gitの場合は,分散系なので,RepositoryがRemote Repository(中央,マスター.みんながアクセス可能)だけでなく,Local Repositoryと呼ばれるRepository(自分以外アクセス不可)が各々のPCの中にもあります.
なので,Remote Repositoryへデータを保存するには,
ファイル編集→Add(処理するというフラグを立てる)→Commit(Local Repositoryに変更を保存)→Push(Local Repositoryの変更をRemote Repositoryへ登録)
という作業が必要になります.
LocalにRepositoryの全情報がありオフラインでもログを漁れたりだとか,Commitは誰にも見えないのでCommitが気軽にできる(と言われている)とか,いろいろいい面もある一方,複雑ですしめんどくさかったりします.
個人的には,一人で開発するようなときなどはSVNのほうがいいな,と思っており,(Repository内のサブディレクトリの使用自由度も高いし)
このブロブシステムもSVNで管理,デプロイされていたりします.
こういうのは結局の所,いくら入門ドキュメントを読もうが,人から教わろうが,
必要なときに,自力で公式ドキュメントの必要な項を見つけ出し,自力で必要な情報を理解できるか,にすべてがかかっているような気がしています.
というわけで,公式ドキュメントを張っておきます.
TortoiseSVN - Online documentation (日本語版)
なにか気になったときは,これを参照しましょう.
実際にいじったほうがわかりやすいので,一連の流れを試してみましょう.
普通はどこかのサーバーにあるRepositoryですが,別に自分のPCにあったって問題ないので,今回はRepositoryを作るところから始めます.
適当に,U:\RemoteRepo
にでも作りますか.
右クリック→TortoiseSVN →Create repository here | |
Create folder structure をクリック.これで,基本的なフォルダ構成が勝手にできる |
U:\WorkingCopy
を使うことにします.
右クリック→SVN checkout... |
これでWorking CopyがTrunkになりました.(もちろんなにもないけど)
このとき,ルートに.svn
という隠しフォルダができます.ここにCommitなどに必要なRepositoryの情報が格納されており,裏を返すと,このフォルダを消すとこのWoriking CopyとRepositoryとの関連付けは解除されます.
適当なファイルを用意する. |
適当に次の2つのファイルをCommitしてみましょう.
#include "./hoge.h" int main(int argc, char *args[]) { printf("Hello, world!\n"); return 0; }
#include <stdio.h>
右クリック→SVN Commit... →コミットログをいれて,OK |
コミットログは,変更内容を完結に記しましょう.何も書かないのはNGです.
最初のコミットが終わりました.
さて,今のままでは,ただ世界に挨拶しているだけなので,Branchを切ってどんどん実装していきましょう.
右クリック→TortoiseSVN →Branch/Tag... でBranchを切る |
Repositoryの /branches/
ディレクトリの配下に,see_you
というフォルダを切って,ここにBranchを作りましょう.
Branchを切るのもCommitなので,しっかりログは下記ましょう.
右クリック→TortoiseSVN →Switch... でBranchにSwitch |
これでWorking Copyはsee_you Branchになったので,適当にコードを編集していきます.
追加実装→Commit |
適当に実装し,同様にCommitする画面を出したとき,下には変更があったファイルのみ(ここではmain.c
のみ)表示されます.
さらに,そこをクリックすると,変更差分 (Diff) が見られるので,これで確認すると良いでしょう.
この調子でじゃんじゃか実装していきます.
Branchでの開発が一段落したら,TrunkへMergeします.
Working CopyをBranchからTrunkへSwitch |
右クリック→TortoiseSVN →Merge... →Merge a range of revisions →Branchを選択してMerge |
すると,なんと,TrunkだったWorking CopyにBranchでの変更が加わっています.
TrunkへCommitして完了! |
いつもいつも,自動Mergeがうまくいくとは限りません.
変更が衝突して自動で解決されない状態を,Conflictといいます.
Conflict状態を作るために,
最新のTrunkからshow_time Branchを切り,適当に実装,Commitする. | |
その後,Trunkを直接いじって,Commitする.(本当はTrunkを直接いじるのは控えるべき) |
と作業しました.
するとRepositoryは次のようになりました.
#include "./hoge.h" int main(int argc, char *args[]) { int i = 0; printf("Hello, world!\n"); for (i=0; i<10; ++i) { if (i%3 == 0) printf("%d\n", i); } printf("Good bye...\n"); return 0; }
#include <stdio.h>
#include "./hoge.h" int main(int argc, char *args[]) { printf("Hello, world!\n"); time_t t = time(NULL); printf("%s", ctime(&t)); printf("Good bye...\n"); return 0; }
#include <stdio.h> #include <time.h>
さて,この状態でshow_time Branch→TrunkへMergeしてみます.
すると,
hoge.h
は自動でMergeされましたが,main.c
がConflictしてますね.
3つの選択肢が提示されます.
Local (Merge先.Working Copy. この場合Trunk) のファイルを使うか,
Repository (Merge元.この場合はBranch) のファイルを使うか,
はたまた編集するか.
ちなみに,このときのWorking Copyはこんな感じになっています.
普通は,Edit Conflict
を選び,左にRepository,右にLocal,そして下にMerge後を配置し,
適当に右クリックでもしながら手動でMergeしていきます.
手動Mergeがおわって,保存できたら,元の画面に戻り,Resolved
を押しておきましょう.
最後にRepositoryブラウザとコミットログを見て終わりましょう.
ともに,Working Copy内の任意のディレクトリで右クリックをすると出せます.
Repositoryブラウザは,SwitchやMergeでディレクトリを選択するときに出てきた画面です.
現在のRepositoryが俯瞰できます.
Branch一覧を確認したり,特定のファイルだけを拾ってきたり,不要になったBranchを消したりします.
Working CopyやRepositoryブラウザの任意のディレクトリで右クリックをすると,コミットログが見えます.
上の図を見てわかるように,ログを表示するディレクトリによって,表示対象となるファイルが変わります.
実は,指定したディレクトリ配下のファイルに対するログが出ていて,1枚目はRepository root,2枚めは/trunk
でログを表示させています.
その他,Tipsや周りの同期などを見ていて感じていること,よく聞かれることなどをまとめておきます.
Repositoryブラウザを見ていて気づいているかもしれませんが,Trunk,Branch以外に,Tagというものがります.
ざっくりいうと,Commitできない(正確に言うと警告は出るができる)Branchで,用途は意味のあるバージョンの保存用です.
例えば,アルファ版,リリース初版,第一回試験用コード,などなど,特定のリビジョン(バージョンに一意に振られる番号)へのアクセス性を高めるためにあります.
といいつつ,SVNの内部実装的には,Trunk,Branch,Tagの区別はなく,これらのディレクトリに並列に他のフォルダも切れますし,これらもRepositoryルート以外にも配置することが可能です.
そんな仕様なので,さらにはCheckout,Switch,Merge,Commitも,任意のディレクトリ単位でできてしまったりします.(例えば, /branch/Database/
のBranchを切ったり,Commitしたりできる.)
じつは,(Gitと異なり)SVNはかなり自由度が高いのです.
Repository全体をCheckoutしている人をちらほらみかけます.やめたほうがいいです.
その状態でBranchを切ったら,PCの中にTrunkとBranchが両方存在していることになります.
普通,このプロジェクトのコードのWorking CopyはPC上のこのディレクトリ,と決めてしまって,そこをSwitchすることによりRepository内を行き来して作業します.
これらのメリットは,例えば,
Working Copyを小さくできる. 冷静に,関係のないBranchまで手元にあって,他人のCommtでWorking Copyの鮮度が落ちるの,煩わしくないか? | |
一時ファイルを共用できる. 例えば,Branchでビルドして,TrunkにMergeしてTrunkでビルドかけるとしよう.Repository全体をCheckoutしていたら,ビルド時間はまるまる2回分かかる. しかし,Switchで切り替えれば,バージョン管理外の中間ファイルの一部は更新不要となり,2回目のビルド時間は大幅に短縮できる. ビルドに小一時間とかかかるときには絶大なインパクトがある. | |
後述するignore-on-commit などの,プロパティ設定が1度で済む.TortoiseSVNの設定類はSwitchしても引き継がれるので,常に同じ環境化で任意のBranch(Trunk,Tag含む)を操作できる. | |
エディタ的にも楽. エディタの設定はプロジェクト毎にできる.例えば,Repository Aのコード規約はスネークケースで文字コードはSJIS,Repository BではキャメルでUTF-8,みたいなとき,エディタの設定的にも,編集するコードは常に同じディレクトリにあったほうが楽. | |
複数のRepositoryをCheckout(Git的な言い回しの,Cloneのほうが伝わるか?)して動かすようなプロジェクトの場合,そもそもSwitchしないと成り立たない. どういうことかというと, ─project root ├─repo 1 ├─repo 2 └─repo 3 のようなディレクトリ構成で動くシステムの場合(ROSとか,結構こうなりがちなイメージ),自分はrepo 1をメインで開発していて,repo 1のBranchで開発していて,ときにはTrunkで動かしたい,みたいなとき,Switchしないと無理. |
などなど.
SVNで管理されているファイルやディレクトリには,プロパティとしていくつかのメタ情報も管理されています.
もっともよく使うのは,ディレクトリのプロパティである,ignore
でしょう.
たとえば,コンパイルしたときにできる中間生成物や,バイナリ,さらにはバージョン管理する必要性のないメディアファイルなどを,このignore
に登録してあげると,Commit時の変更ありファイル一覧に表示されなくなりますし,Repositoryからも削除されます.
設定の仕方は簡単で,登録したいファイルやディレクトリを右クリックし,Add to ignore list
を選択し,登録の仕方(再帰的なのか,とか,拡張子指定なのか,とか)を選べばいいだけです.
一方,Gitの場合は,.gitignore
という隠しファイルで一元的に管理しています.
個人的には,Gitの方が使いやすいt感じます.
ignoreに関連して,何をバージョン管理して,何をバージョン管理外とするか,は結構難しい問題ないですが,基本的には,一意に生成可能なファイルや,バイナリはバージョン管理外でいいと思っています.
(もちろん配布用バイナリなどは除く)
シミュレーションの設定値とその出力や,可視化したグラフなどは,別途保存したほうがいいと思っています.
そもそも論として,そういうもののDiffをとっても嬉しくないと思いますので.
(SVNではなく)TortoiseSVNの機能として,管理リスト,という機能があります.
その中でも最も有益なのが,ignore-on-commit
だと思います.
下の図を見てください.
modified
となっているファイルがたくさんありますが,下側のはデフォルトではチェックが付いていないので,そのままOKを押すとCommitされません.
これは,ignore-on-commit
という管理リストに属しているからで,この画面で該当ファイルを右クリックし,Move to changelist...
を選択することによって登録可能です.
どういうものを設定するべきかというと,自分のテスト環境やビルド環境では変更しうるが,Commitするのは避けたいもの,
具体的にはIDEのユーザー設定(watch listとか,ブレークポイントとか),デフォルトセッションとか,試験Config情報とかです.
これで,「あ,間違えてポート設定をCommitしてしまって,他の人が試験するときに迷惑かけてしまった...」などが防げます.
コミットしたい場合は,下のリストからチェックを入れればいいだけです.
Branchの鮮度が落ちすぎると,TrunkへのMergeが極めて大変になります.
そういうときに備えて,GitであればRebaseすればいいのですが,SVNにはあいにくそんな機能はありません.
ただ,ちょっと考えれば,TrunkからBranchにMergeすればいいだけ,だと気づきます.
(前述のとおり,SVNの実装にTrunkもBranchもTagも区別はない.)
Trunkに大幅アップデートがかかったときや,TrunkへMergeする前のBranchでの実機試験前などにTrunkからMergeするのはおすすめです.
Conflict,めんどくさいです.
上でEdit Conflictの方法を記しましたが,極めてめんどくさい事などもあります.(例えば,Excelとかマージするとき(なんでRepositoryにExcelがあるんですかね...))
そういうときに僕がよくやるのは,
“自分の実装したコードは他人が実装したコードよりも把握している”ということを前提に,prefer local
をつかってしまう,ということです.
詳しく説明すると,
TrunkへMergeする際,Working Copyには最後に他人が実装したTrunkがあります.
Conflictが発生したら,prefer theirs
で自分のファイルをぶち込むのではなく,とりあえずprefer local
で他人の編集を受け入れ,その後手動で自分の書いた部分をコピペしていっています.
そうすることによって,被害が最小限に抑えられると思っています.
意外とよく使う機能です.
ファイル単位やディレクトリ単位で,Working Copyの変更を取り消す機能です.
ぐだぐだになったので消してしまいたいときとか,Switch前にWorking Copyをきれいにしておきたいときなどに使えます.
うまく使えば(IDE関連ファイルなどに行うなど),不要なConflictを減らせます.
ハードウェアに関わるソフトを開発している場合,実機テストが容易ではないので,とてもむずかしい問題だと思っています.
一応,こんなもんかな,と考えているのは,次のとおりです.
試験(SILS,実機)のどちらもしていないものは当然NG | |
HW依存部分は実機試験しないとNG | |
HW非依存である部分でかつ,周囲への影響が少ないものはSILSで十分検証されていてば,OK(もちろん後日試験は行う.) | |
Mergeのコストが高くなるなど,デメリットが大きい場合でかつ,普段使わず,特定の関数を叩かないと絶対に実行されないものに関しては,許容せざるを得ない |
ただ,正直境界は曖昧です.
研究室で生きていくために,SVNの簡単な使い方をまとめました.
バージョン管理は極めて強力なので,研究のソースコードだけでなく,論文の原稿などにも使っていくことをおすすめします.
バージョン管理ツールは,どのバージョンにも好きに戻せる,つまりぶっ壊すことはないので,ガチャガチャいじってなれていってください.
名前
Email (※公開されることはありません)
コメント