!! 目的 ソフトウェアをグループで開発する際,バージョン管理を行うことは必須でしょう. バージョンを管理してくれるソフトウェアはいくつも知られていますが, 本講義では subversion (svn) を使ってもらっています. Subversionの復習を行い,もっと効果的にsubversionを使ってもらうことが本講義の目的です. このページは [[svn::簡単な使い方]] を基に作成しました. !! Subversionの利用したソフトウェア開発の概要 Subversionを使う際の概要を図示すると以下のようになります. ((img outline.png 500)) 図において,班員達は,共有ディレクトリを更新(チェックアウト,コミット)しながらソフトウェア開発を行っています. この共有ディレクトリのことを((color red リポジトリ))といいます. 正確には,バージョン管理されたディレクトリです. リポジトリの中には,グループで開発したプログラムソースやドキュメントなどが格納されています. 本講義では,このリポジトリをどのように更新していくのかを解説することで, subversionを利用したソフトウェア開発の流れの一例を解説します. //* [[サブバージョンの使い方]]を参照のこと. //* リポジトリ,ワーキングコピー,リビジョン,チェックアウト,コミット,などの単語の意味を理解すること. //** 普段の作業は,リポジトリからチェックアウトしたワーキングコピーの方を使う.'''リポジトリそのものには手を触れない'''. //** ある程度の完成度まで到達したら,ワーキングコピー(中の修正したファイル群)の内容をリポジトリに反映させる.これがコミット. //** コミット時には,どのファイルを,どのように修正したか,といった内容をログに残しておく. //** 別の人間が,同じファイルを別々に修正して,それぞれでコミットしようとすると衝突(コンフリクト)する //*** コンフリクトは,手動で対処する以外に方法はない. !! ワーキングコピーの取得: svn checkout ソフトウェアを開発する際,リポジトリに格納されているファイルを直接に編集することは行いません. リポジトリの中身を,いったん,ローカルディレクトリにコピーして, コピーしたファイルを編集します. このローカルコピーのことを((color red ワーキングコピー))とか,((color red 作業コピー))と呼びます. まずはリポジトリからコピーを取得する操作を行ってみましょう. コピーしたいディレクトリに移動して'''checkout'''します. 仮に,~/csd 以下に, proj という名前のワーキングコピーを展開するとすると, 8< % cd ~/csd % svn co https://svn.cis.iwate-u.ac.jp/svn/csd/proj >8 !! ワーキングコピーの更新: svn update 複数の人間で開発を行なう場合,'''編集作業を行う前に必ず''' ワーキングコピーに(リポジトリの)最新情報を反映させる必要がある. 8< % cd ~/csd/proj % svn update >8 !! ワーキングコピーの状態確認: svn status ワーキングコピーの状態を確かめるには, (ワーキングコピーが存在するディレクトリ以下で) 8< % svn status >8 とする.先頭のマークで状態が分かる. 6< :? ::どんな状態か分からない.(例えば,ワーキングコピーディレクトリ下に新たにファイルを作成したが,svn addしていない場合,とか) :A ::追加 :D ::削除 :C ::衝突 :M ::変更 :! ::バージョン管理下で,ファイル,ディレクトリが不完全,または失われている.svn のコマンド以外でファイルを消去したりするとよく起こる.svn revertなどを使って回復できるが,revertコマンドは「変更を破棄してしまう」という意味で本質的に危険なので,多用しないこと.(!フラグが出ないように気をつけてファイル管理すること) >9 !! ワーキングコピーに対する修正変更をリポジトリに登録: svn ci 自分が加えた修正をリポジトリに反映させるには,次のように'''svn ci'''を実行する. 8< (proj内のxxx.cを修正して登録する場合の例) % cd ~/csd/proj % emacs xxx.c % svn ci -m 'コミットメッセージ' >8 「コミットメッセージ」には,何を変更したかを書いておく('''他の共同開発者にわかるように''') まったく無意味なメッセージを書くことは極力避けるべきです. * commitする際には必ずメッセージが必要だ,と覚えておこう. !! ファイルやディレクトリを新規に追加する ディレクトリ(dir1)を新たに追加したい場合は, 8< % svn mkdir dir1 >8 のように,'''svn mkdir'''とすること.また,ファイル(a.txt)を新たに追加したいときは, リポジトリに反映させるために 8< % svn add a.txt >8 のように'''svn add'''とすること.ただし,'''これらが真にリポジトリに登録追加されるのはcommitした時点'''なので注意. (commitするまではリポジトリは以前の状態のまま) !! ファイルやディレクトリを削除する 8< % svn remove a.txt >8 これも,実際に削除が反映されるのはcommit時なので注意. !! ファイルやディレクトリの名前を変更する 8< % svn move a.txt b.txt >8 これもcommitすると反映される. !! 変更内容のチェック 自分が変更したファイルと,リポジトリに登録されている最新版とを比較するには, 8< % svn diff a.txt >8 とする. !! 作業ログの閲覧 開発履歴は log オプションで確認できる.(ここで表示されるメッセージは,commit時に -m オプションで書きこまれたもの) 8< % svn log a.txt >8 !! 競合とその解決 同じファイルを複数人が編集した場合,ファイルに不整合が生じてしまいます. これを((color red 競合))と呼びます.ここでは競合を解決するためのsubversionの機能を解説します. ただし,本質的な解決は,競合を引き起こした開発者同士で話し合う必要があるかもことに注意しましょう. (きちんとした作業分担が行われていれば, 実際の開発において競合はほとんど起こらないと言われています.) 次のような状況を考えましょう.サブ君とバージョン君は同じ班に属しています. サブ君とバージョン君の2人が同じプログラムファイル fruits.c を編集してしまったとします. サブ君,バージョン君,それぞれがリポジトリへのコミットを行ったのですが, 偶然にも * はじめに,サブ君が fruits.c のコミットを行って, * 次に,バージョン君が fruits.c のコミットを行った. という状況を再現して解説します. ! 編集箇所が重ならない競合 Subversionは,サブ君,バージョン君,それぞれの変更を両方とも採用したプログラムファイルを自動で作ってくれます. バージョン君がコミットしようとすると, 8< % svn ci -m "Massages" 送信しています fruits.c svn: E160042: コミットに失敗しました (詳しい理由は以下のとおりです): svn: E160042: ファイルまたはディレクトリ 'fruits.c' はリポジトリ側と比べて古くなっています。update を実行してみてください svn: E160024: resource out of date; try updating >8 と怒られます.Subversionの指示通り「svn update」を実行してみましょう.すると,以下のようになります. 8< % svn update Updating '.': G fruits.c リビジョン xxxxx に更新しました。 >8 ここで「G」はファイルが問題なくマージされたことを意味します. fruits.c の中身を見てみると, サブ君の修正内容とバージョン君の修正内容とがどちらも反映されているはずです. ! 編集箇所が重なってしまった競合 Subversion は,開発者にいくつかの選択肢を与えてくれます. サブ君とバージョン君は,fruits.c の同じ箇所を修正してしまったとします. はじめにコミットを行ったサブ君は,競合のことを気にせずコミットを完了させるでしょう. しかし,続いてコミットを行ったバージョン君は,コミットできずに困ってしまいます. 8< (バージョン君が実行している状況を想定して下さい) % svn ci -m "Massages" 送信しています fruits.c svn: E160042: コミットに失敗しました (詳しい理由は以下のとおりです): svn: E160042: ファイルまたはディレクトリ 'fruits.c' はリポジトリ側と比べて古くなっています。update を実行してみてください svn: E160024: resource out of date; try updating >8 また怒られてしまいました.Subversionの指示通り「svn update」を実行してみます. 8< % svn update Updating '.': '***(ローカルディレクトリのパス名)***/fruits.c' で競合が見つかりました。 選択: 延期 (p), 全差分 (df), 編集 (e), 衝突自分 (mc), 衝突他人 (tc), , すべてのオプションを表示 (s): >8 すると,いくつかの選択肢が表示されました. 競合が起きているファイルに対してどのような処置を施すのかを聞かれています. まずは,どのような競合が起きているかを確認するために「df」を選択してみましょう. 8< (競合が起きている場所の内容が表示されます.) ..... ..... ..... 選択: 延期 (p), 全差分 (df), 編集 (e), 解決版 (r), 衝突自分 (mc), 衝突他人 (tc), , すべてのオプションを表示 (s): >8 さぁ,ここからが本番です.どうにかして競合を解決しなければなりません. すぐに解決策が分かるならば問題ありませんが,ほとんどの場合, 開発者同士の話合いが必要になると思います. 修正内容を決めることをいったん保留にするために, 「延期(p)」を選択したとします. すると,いくつかのファイルが自動で生成されます. 「fruits.c.mine」「fruits.c.rxxxxx」です. それぞれ,作業コピーのファイル,リビジョンxxxxxのファイルに対応しています. ここで注意して欲しいのは,((img color fruits.c の中身が自動で変更されていて)), 衝突が起きている箇所は以下のように変わっているはずです.見てみましょう. 8< +<<<<<<< .mine + + (自分の作業コピー上の内容) + +======= + + (リポジトリ内の内容) + +>>>>>>> .rxxxxx >8 上の「<<<<<<<」と「>>>>>>>」を((color red 競合マーカー))と呼びます. 続いて,バージョン君は,サブ君の席へ行き,競合を解決するための話合いを行います. 話し合いの結果,バージョン君の修正が正しいことが判明したとしましょう. その場合,次のようなコマンドを打ちます. 8< % cp fruits.c.mine fruits.c % svn resolved fruits.c >8 これで,衝突が解消されました. Subversionが自動で生成したファイルは消されているはずです. ここで「svn resolved」は,衝突が解決されたことを subversion に通知するコマンドです. 衝突を解消する方法はいくつもありますが,最も代表的と思われるシチュエーションを解説しました. !! 参考文献 * Subversion実践入門 第2版 Mike Mason著/でびあんぐる監訳