2011年11月24日

Subversionユーザーがgitの考え方を勉強した

Subversionを使ってるのにワザワザGitを使おうと思ってる理由は下記の利点を享受する為。

・マスターリポジトリのログを綺麗にしたい!
 commitって意味のある単位でするのがベストだとは思うけど、バックアップの意味合いもあってコミットする時もある。そうするとログが大量になってもう読む気なくなる。
・変更更新を早くしたい!
 サーバーへのコミットって重いじゃないですか。
・気軽にbranchとかtagとか使いたい!
 ローカルリポジトリでbranch,tagが作ったり削除したりできる。
・コミットの制御が柔軟にしたい!
 「あっち直してー、こっち直してー。でも今日提出あるからねー」とかあるわけですよ。Gitだと「インデックス(staging area)」を上手く使えば柔軟に制御できそう。


Gitに関してはWeb上に山ほどArticleがあるので、超ざっくり自分メモ。

Gitの構成要素


・マスターリポジトリ
 みんなで使う大元のリポジトリ。Subversionでのリポジトリと思ってOK
・ローカルレポジトリ
 個人が使うリポジトリ。
・インデックス(staging area)
 ワーキングコピーの状態をインデックスという場所に格納する。ここからローカルリポジトリにコミットする
・ワーキングコピー
 実際にコーディングしたりファイルを追加したりする場所。Subversionのワーキングコピーと一緒

Subversionから「ローカルリポジトリ、インデックス」という要素が増えてますね。

Gitの手順


・マスターリポジトリ作る
Subversionだと「svnadmin.exe create . 」に該当
 

> git init

・「インデックス、ローカルリポジトリ、ワーキングコピー」の作成
Subversionだと「svn checkout file:///****/****」に該当

> git clone file:///***/****


・変更内容をマスターリポジトリに反映するまで
 1.ファイルを追加or更新する
  変更するファイルを作らないとしょうがない
 2.「ワーキングコピー→インデックス」の反映
  Subversionの場合はいきなりコミットでマスターリポジトリに反映ですが、Gitではまずインデックスに反映させます。

カレントディレクトリ以下の全てのファイルの変更&追加をインデックスに反映

> git add .

 3.「インデックス→ローカルリポジトリ」の反映
  次に、ローカルリポジトリに変更を反映させます。

  

> git commit -m "test commit"

4.「ローカルリポジトリ→マスターリポジトリ」の反映
後は最後にローカルリポジトリ→マスターリポジトリをすれば終了

  

> git push
  


めんどーーーーい。Subversionに比べてめんどーーーーーい。
・変更内容をマスターレポジトリから取得する
朗報。コレはコマンド一発。

> git pull

Subversionでいうupdate

Subversionとの用語差分


Gitをお勉強しているとSubversionと同じ用語で意味が違うのがいくつかあって混乱するので主なものをまとめてみた。
・add
Subversion:「ワーキングコピー→マスターリポジトリ」のファイル追加
 Git:「ワーキングコピー→インデックス」の状態登録
・commit
Subversion:「ワーキングコピー→マスターリポジトリ」の変更登録
Git:「インデックス→ローカルリポジトリ」の変更登録
・diff
Subversion:「ワーキングコピーとマスターリポジトリ」の比較
Git:「ワーキングコピーとインデックス」の比較(diff HEADでワーキングコピーとローカルリポジトリ)
・checkout
Subversion:「マスターレポジトリ」から「ワーキングコピー」を作成する。(Gitだとcloneに該当)
 Git:ブランチの作成

とりあえずコレで最低限使えるのかな。ここまでだと、Subversionに比べてややこしいだけな感じだけど、各コマンドの詳細な使い方を勉強するとどんどん便利になっていきます。


【関連する記事】
posted by purigen at 11:00| Comment(0) | TrackBack(0) | Git | このブログの読者になる | 更新情報をチェックする

2011年11月17日

「関数型は再帰関数めちゃめちゃ使うよ」と聞いて心配になる事(in Scala)

「関数型は再帰関数めちゃめちゃ使うよ」と聞いて心配になる事(in Scala)

C,C++,Javaとかをメインとしてやってる人が関数型について

「関数型は変数の値変更を良しとしない言語だから再帰関数を多用するよー」

って聞くと、即座に思い浮かぶ懸念は、

1.えっ、再帰関数多用って関数呼び出しコストどうするのよ?重いよねそれ?
2.えっ、再帰関数多用すると何処でスタックオーバーフローするか分からないし怖いよ。

だと思うんですよ(私はそうでした)。 Scalaは関数型も書ける言語なのでどうなのかというと結論からいうと

「大丈夫。気にすんな」

です。 Scalaでは「末尾再帰の最適化」がサポートされています。再帰関数の最後で自分自身を呼び出すようにすればコンパイル時に最適化されるのです(単純にwhileみたいに置き換えられる)。 ですので、

・関数呼び出しコスト
・スタックオーバーフロー

は大丈夫なのです。

論より証拠。 

◆テストコード1
単純に数値カウントアップするだけ

非再帰

var i = 0
while(i <= high){
i += 1
}

再帰

def countUp(now: Int,high: Int):Int={
if(now <= high) countUp(now+1, high) else now
}
val i = countUp(0,high)


◆テストコード2
下限値(low)から上限値(high)までの合計値を求めるコード

非再帰

var sum = 0
var i = low
while(i <= high){
sum += i
i += 1
}
println("sum="+sum)

再帰

def sumRange(sum: Int,now: Int,high: Int):Int={
if(now <= high) sumRange(sum+now,now+1,high) else sum
}
val sum = sumRange(0,low,high)
println("sum="+sum)



で、ベンチマーク取ってみる

object CompRecursive{
import scala.testing.Benchmark
def main(args:List[String]){
//カウントアップバージョン
test1(100000000)
//合計計算バージョン
test2(0,100000000)
}
//テスト1:ただのカウントアップ
def test1(high: Int){
println("countUp")
val benchmarkNoRecursive = new Benchmark{
def run={
var i = 0
while(i <= high){
i += 1
}
println("count="+i)
}}
println("非再帰関数バージョン処理時間="+benchmarkNoRecursive.runBenchmark(1)(0)+"(/ms)")
val benchmarkRecursive = new Benchmark{
def run={
def countUp(now: Int,high: Int):Int={
if(now <= high) countUp(now+1, high) else now
}
val i = countUp(0,high)
println("count="+i)
}}
println("再帰関数バージョン処理時間="+benchmarkRecursive.runBenchmark(1)(0)+"(/ms)")
}
//テスト2:合計求める
def test2(low: Int,high: Int){
println("calculate sum")
val benchmarkNoRecursive = new Benchmark{
def run={
var sum = 0
var i = low
while(i <= high){
sum += i
i += 1
}
println("sum="+sum)
}}
println("非再帰関数バージョン処理時間="+benchmarkNoRecursive.runBenchmark(1)(0)+"(/ms)")
val benchmarkRecursive = new Benchmark{
def run={
def sumRange(sum: Int,now: Int,high: Int):Int={
if(now <= high) sumRange(sum+now,now+1,high) else sum
}
val sum = sumRange(0,low,high)
println("sum="+sum)
}}
println("再帰関数バージョン処理時間="+benchmarkRecursive.runBenchmark(1)(0)+"(/ms)")
}
}
CompRecursive.main(List(""))

私の環境だとこうなった

countUp
count=100000001
非再帰関数バージョン処理時間=93(/ms)
count=100000001
再帰関数バージョン処理時間=63(/ms)


calculate sum
sum=987459712
非再帰関数バージョン処理時間=141(/ms)
sum=987459712
再帰関数バージョン処理時間=110(/ms)

マジかよ再帰使ったほうが速いっ。
posted by purigen at 00:00| Comment(1) | TrackBack(0) | Scala | このブログの読者になる | 更新情報をチェックする
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。