diredの罠

emacsでdiredを立ち上げて、

!mv DIRNAME 

とかやったら、rm -rf された。
消えたのはコードスニペットフォルダ。


幸いGithubにある程度残ってたので、そこから70%程度復旧。
'!' なんてもう使いません。

2009/06/07 23:50 追記

diredで上記のコマンドを実行した時に、カーソルが合っていたディレクトリ (TARGETDIR) へ mv されていた。
つまり、上記のコマンドは

! mv DIRNAME TARGETDIR

という動作になっていた。

無知は罪です。dired様ごめんなさい。

elscreenを使う

emacs 上でGNU screenみたいな動作ができるらしい。Meadowのパッケージに含まれていた。
Macでも使いたいので入れてみる。

apelが必要なのでそれも入れる。

apel

http://cvs.m17n.org/elisp/APEL/index.html.ja.iso-2022-jp

$ make
$ make install LISPDIR=~/lisp VERSION_SPECFIC_LISPDIR=~/lisp/emu

(2009/06/20 インストールディレクトリを修正)

elscreen

Fragments of Reality - ElScreen

tarボールを落としてきて開封。
とりあえずはelscreen-gfだけ使う。

(add-to-list 'load-path "~/lisp/elscreen")
(require 'elscreen)
(require 'elscreen-gf)

なんていうかもう、とてもとても快適です。

magit.el を試してみた

egg.elいまいちーと書いたところ、

@gom egg.elが嫌ならmagit.elでどう?俺的にはそっちのが使いやすいけど。

http://twitter.com/rubikitch/statuses/1901340067

id:rubikitch さんに教えてもらいました。ありがとうございます。
というわけで、早速試してみた。

インストール

makeするのね

$ git clone git://github.com/jdhuntington/magit.git
$ ./autogen.sh
$ ./configure --prefix=$HOME/lisp/magit
$ make
$ sudo make install

.emacsの書き換え

(add-to-list 'load-path "~/lisp/magit/share/emacs/site-lisp/")
(require 'magit)

git status

statusバッファ上でキー操作を行う。
キー操作は以下の通りで、大体の操作はできる模様。

違うbranchにpushするとか、refspecをごちゃごちゃいじる辺りはどうなってるのか不明。

Magit User Manual

M-x magit-status
  • TAB: セクションの表示を切り替える
  • M-1, M-2, M-3, M-4: セクション表示の切り替え
  • Section: Untracked file
    • s: ファイルをステージに追加する(git add)
    • i: .gitignoreにファイルを追加する
    • C-u i: ignoreファイルを指定する
    • I: .git/info/excludeにファイルを追加する
    • k: ファイルを削除する*1
  • Section: Unstaged Changing / Staged Changing
    • s: ファイルをステージに追加する(git add)
    • S: 全ファイルをステージに追加する
    • u: ファイルをステージから降ろす
    • U: 全ファイルをステージから降ろす
    • k: 変更を取り消す
    • c: コミットログを書く
    • C: コミットログをチェンジログ形式で書く?
    • C-c C-c: コミットする(git commit)
    • C-c C-a: コミットをやり直す(git commit --amend)
  • Log
    • l: ログ一覧を表示する(git log)
    • L: 詳細ログの一覧を表示する(git log --stat)
    • ログを選択して RET: ログの詳細を表示する(git log -p)
    • a: コミットを今のブランチに適用する(git cherry-pick & NOT commit)
    • A: コミットを今のブランチに適用し、コミットする(git cheery-pick & git commit)
    • v: コミットを取り消す(git revert)
    • C-w: コミットのsha1ハッシュをコピーする
    • =: 今のコミットとの差分を表示する
    • .: コミットをマークする
  • h or H: 今のHEADまでのログを表示する
  • d: ワーキングコピーからあるコミットまでの差分を表示する(git diff)
  • D: 2つのコミットの差分を表示する
  • t or T: タグを作成する(git tag)
  • x: コミットを取り消す(git reset --soft)
  • X: コミットと変更を取り消す(git reset --hard)
  • Stash
    • z: stashを作成する(git stash)
    • a: stashを適用する(git stash apply)
    • A: stashをpopする(git stash pop)
    • k: stashをdropする(git stash drop)
  • b: ブランチを切り替える(git checkout)
  • B: 新規ブランチを作成して切り替える(git checkout -b)
  • w: wazzup?
  • m or M: マージを行う
    • X: 手動マージを中止する
    • e: resolved conflict?
  • R: rebase
  • P: push (default remote, current branch)
  • f: git remote update
  • F: pull
  • git svn
    • N c: git svn commit
    • N r: git svn rebase

後半は疲れてしまったのでかなり適当です。
必要なコマンドは押さえられていて、いい感じに扱えそう。

*1:物理的に削除されるようだ

久々にEmacsをいじくってみる

Textmateも便利でいいのだけど、補完機能とか考えるとやっぱりEmacsだなーと思い始めた今日この頃。


とりあえず anything と rcodetools に慣れると幸せになれそう。

Git 勉強会@万葉 #3 に行ってきた

最近勉強会レポートしか書いてないけど気にしない。
iwamatsu さんによるコンフリクト大会に参加してきました。

以下メモ晒し。

テーマ

あなたとコンフリクトしたい!

  • 分散リポジトリとコンフリクトとバージョン管理
  • チームを組んでコンフリクト大会
    • git pull / git rebase / git push

はじめのおやくそく

Git は「ぎっと」と読みます!!!

簡単なコンフリクトと修正

  • 各チームがそれぞれリポジトリを取ってきて、データを追加する
  • git commit
  • git checkout -b test
  • git pull #=> コンフリクト!
    • git fetch + git merge
    • ローカルブランチに pull 先の情報を上書きする
  • なぜコンフリクトしたのか?
    • 同じところにマージしようとしているから
  • コンフリクトを修正
  • git add FILE, git commit
  • git log で確認 #=> merge 分のログもはいっている。
    • 全員コミットログの順番が異なる。
    • コミットログは時間軸で表示される
    • git log --topo-order #=> コミット順で表示される
    • 次々と pull

やってみた結果・・・

  • 人によってファイルの内容が違う
    • 好き勝手に pull と編集をしたため
  • お互いに主導権を持って pull し合うと、バージョン管理できない!!
    • => 自分のものが常に最新になってしまう
    • 同じファイルにならなければ、「バージョン管理」ではない
  • 解決 (バージョン管理) するには?
    • どこかでまとめる
    • 管理者を決める

clone 先にまとめてみる

  • git push #=> reject!
    • push 先を誰かが更新していた
    • 間のコミットが抜けているため、整合性がとれない!
    • force オプションでコミットすると、間のコミットが消えてしまう・・・
  • force を効かないようにはできないの?
    • hook で「足りないオブジェクトがあったら push させない」ということはできる

push のエラーを修正しましょう

  • git remote update #=> リモートリポジトリのデータを取得する
    • git fetch と似てる
  • git rebase origin master
    • リモートの変更を元に、自分の変更を適用する
    • またコンフリクト!!
  • セクション別に修正する
  • git rebase --continue
    • 自分の変更を適用している最中にコンフリクトすると、 rebase が止まる
    • 自分のコミットを 1 つずつ適用しているから。
    • 再開するには --continue
    • 全部のパッチが適用されるまで、延々 git rebase --continue ...
    • rebase できた!
  • 相手の変更を尊重しましょう。
    • 自分の修正の内容はわかる。相手の修正に自分の修正を加える
    • git pull は自己中。複数のコミッタがいるならダメ絶対
    • git pull --rebase
    • git update remote & git rebase
      • merge: 自分が主体。自分のを元に相手の変更を適用する。
      • rebase: 相手が主体。相手のを元に自分の変更を適用する。
    • git merge した後に git rebase すると、 rebase した状態になる。

その他の方法

  • git pull してもらう
    • git request-pull
  • パッチで取り込んでもらう
    • git format-patch でパッチ作成、送信
    • 管理者が git am で適用

質疑応答

  • Q. マージは絶対ダメなの?
    • 運用にもよるが、立場によっては OK 。 master に近い立場 (取り込む側) はマージする。むしろ rebase しちゃダメ?
    • master を頂点とした階層構造の場合は、そういう感じのルールにしておくとよい。
  • Q. やっぱり大本のリポジトリは必要?
    • あった方が問題は少ない。
  • git cherry-pick pullするファイルを選択する
  • git clean #=> untrack なファイルを削除
  • git tag #=> 任意の blob, tree オブジェクトにリンクするタグを付けられる
  • 空ブランチ (git checkout '') とか


個人的には、Gitが分散であることの意味がすこし見えてきました。
各開発者がパッチを持ち寄って、マスターにがんがんと適用していくのを支援するため、
小回りの効くコマンド群で気持ちよく管理できる。
そんな意図が感じられます。


Subversionの機械くささも頼もしくていいですが、運用ルール次第で形を変えられる
Gitも融通が効いていいのではないでしょうか。


皆様おつかれさまでした!

Git 勉強会@万葉 #2 に行ってきた

5/8 に万葉さんで開催された Git 勉強会に参加してきました。
軽く遅刻しましたが、なんとか参加。


今回は全編 jugyo さんによるライブ git いじり。
前回は reset や stash の使い方など、実際に使う場面で困っている部分を掘り下げていく感じでした。
今回は、 1 人で使う場合の使い方を中心に、ブランチやリモートの概念とかを触ったりしてました。


というわけで、以下メモ晒し。
まとめていないし、ぱっと浮かんだコマンドも追記してしまっているので、
若干ずれてるかもしれませんが、ご容赦を。

Git について軽く

  • なぜ github を使うのか?
    • 個人でやるなら使わなくてもいいよね
    • サーバ用意しなくても手軽に共有できる

実際に Git を使ってみる

Windows の DOS プロンプトだと日本語が文字化けするらしい
tortoiseGit とかいけるんじゃね?

一人で使う
  • 初期化
$git init
  • 設定をする
$git config --global user.name hoge
$git config --global user.email hoge@example.com
$git config --global color.ui auto
  • 状態を確認する
$git st
  • コミットしたいファイルを追加する
$git add . #全ファイル
$git add -u #バージョン管理下にある全ファイル
  • コミットする
$git commit
$git commit -m'Comment' # コメント付き
$git commit --amend # 前回のコミットをやりなおす
  • ログを見る
$git log
$git log -p #差分も表示する。 -u でも可
$git log --stat #変更したファイルの概要
$git whatchanged
$git log --binary #バイナリファイルの差分を見る
  • コミットの内容を確認する

# HASH は 10 桁くらい指定すれば確実?

$git show HASH
$git show -p HASH # 差分も表示する
  • 差分を確認する
$git diff #現在の状態と、コミット予定の状態の差分
$git diff HEAD #現在の状態と、最新のコミットの差分
$git diff --cached #コミット予定の状態と、最新のコミットの差分
  • 取り消し
$git reset #git add したものを取り消す。インデックスのみ
$git reset --hard #全ファイルの変更を元に戻す
$git revert #変更を取り消すためのコミットを作成する
$git checkout HEAD FILENAME # FILE を最新のコミットの状態に戻す
  • バージョン管理しているファイルを見る
$git ls-files
ブランチを使う
  • ブランチを管理する
$git branch #ブランチの一覧
$git branch NAME #新規作成
$git branch -d NAME #削除
  • ブランチを切り替える

index に追加したファイルがある場合に切り替えると、切り替え先のブランチにパッチとして適用される。

$git checkout NAME
$git checkout -b NAME #新規作成&切り替え
  • 現在の index の状態を保存する
$git stash save 'message'
$git stash show 
$git stash list
$git stash apply 
$git stash clear
$git stash drop
$git stash pop
  • ブランチの変更を取り込む

コンフリクトしたら、変更して add して commit 。

$git merge BRANCH
$git merge --squash #最新のコミットだけをマージする
  • タグを付ける
$git tag NAME HEAD
リモートを活用する
  • ワーキングコピーを作成する
$git clone PATH
  • リモートを管理する
$git remote
$git remote add REMOTE PATH
$git remote rm REMOTE
$git remote show REMOTE
  • リモートの変更を取得する

pull だとマージされる。
fetch だと取得内容が FETCH_HEAD に格納される。
REMOTE, BRANCH は省略可能

$git pull REMOTE BRANCH
$git fetch REMOTE BRANCH
  • リモートに変更を反映する

REMOTE, BRANCH は省略可能

$git push REMOTE BRANCH
$git push REMOTE BRANCH:hoge # local の BRANCH を REMOTE の hoge に push する

リモートについて参照: http://at-aka.blogspot.com/2009/02/git-remote-repository-branch.html

Git の状態遷移

コピーしたファイルを変更して add すると index に登録される。
commit すると index に登録されたものがリポジトリに登録される。

Working copy => index (cache) => repo
            add            commit
             <=
	    reset

気軽に Git を使うには?

その他

  • hook が使えるらしい
    • 参照: .git/hooks/*.sample
  • 「何をバージョン管理するか?」をよく考えるべき
    • HEAD がわからなくなると破綻する
    • 親サーバはやっぱり必要?
  • remote のブランチがない場合
    • remote にブランチを作る
    • 既存のブランチに push する
  • 結局、ブランチとリモートがややこしい

次回予定?

  • みんなでコンフリクト大会
  • git と sinatra を使って、実際になにか開発する

やっぱり、実際に複数人で1レポジトリをがんがんいじくりまわしたらどうなるのか?が気になるところです。
その際に発生する問題と、その対処がわかるといいなーなんて思いました。


主催のjugyoさん、会場提供してくださった株式会社万葉さんありがとうございました!
参加した皆様もお疲れ様でした!

Google App Engine で Rails を動かしてみる

Google App Engine (以下 GAE) で Java が使えるようになったため、 JRuby が動作するようになりました。
JRuby on GAE で Rails を動かせる!ということで、あちこちで試みがなされています。

ってことで、先達の記事はいっぱいあるけど、手を動かさないとわからないので自分でやってみました。
案の定色々引っかかったのでメモメモ。

概要

まず、動いている (たぶん) サンプルは以下の URL 。
デモ: http://hello-gae-gom.appspot.com/
ソース: http://github.com/gom/hello-gae-gom/tree/master


こんにちわ!とか表示されたら動いてると思います。
動かない状態になってたらごめんなさい。
データは何も保存・読み出しせず、 Controller からテキストを出力しているだけです。

制限

GAE にはいくつかの制限があります。

  • ファイル数は 1000 まで
  • ファイルサイズも上限がある

これらの制限をクリアして Rails を動かす必要があります。

何すればいいの?

やることはこれくらい。 8 割くらいは Rails Templete がやってくれます。
なお、今回は DataStore は行ってません。

  1. ソフトの準備
    1. jruby (jar の作成・分割)
    2. jruby-rack
    3. warbler (rubygems)
    4. google app engine java sdk
  2. Rails アプリの作成
    1. 普通にアプリを作成
    2. GAE 用に設定を変更
    3. lib を用意
  3. Rails の不要なファイルを削除
  4. GAE 用の XML ファイルを作成
  5. Warbler でサーブレット
  6. デプロイ

というわけで、以下で簡単に手順を紹介。

ソフトの準備

jruby インストール

github より jruby を git clone し、ビルドします。
あとで lib として使う jar ファイル生成も行います。

$git clone git://github.com/jruby/jruby.git
$cd jruby
$ant
$ant jar-complete #=> lib/jar-complete.jar が生成

また、コマンドを簡略化するために、 jruby の PATH を設定しておきます。

#.zshrc
export $JRUBY_PATH=/path/to/bin/jruby
jruby を分割した jar を作成する

下記のスクリプトで jar ファイルを分割します。
jruby-core.jar と jruby-stdlib.jar が生成されます。
via:ぽかぽか陽気 - ずっと君のターン

#!/bin/sh

rm -rf jruby-core.jar
rm -rf ruby-stdlib.jar
rm -rf tmp_unpack
mkdir tmp_unpack
cd tmp_unpack
jar xf ../jruby-complete.jar
cd ..
mkdir jruby-core
mv tmp_unpack/org jruby-core/
mv tmp_unpack/com jruby-core/
mv tmp_unpack/jline jruby-core/
mv tmp_unpack/jay jruby-core/
mv tmp_unpack/jruby jruby-core/
cd jruby-core
jar cf ../jruby-core.jar .
cd ../tmp_unpack
jar cf ../ruby-stdlib.jar .
cd ..
rm -rf jruby-core
rm -rf tmp_unpack
rm -rf jruby-complete.jar
jruby-rack の用意

jruby-rack-x.x.x.jar を作成します。

$ git clone git://github.com/nicksieger/jruby-rack.git
$ cd jruby-rack
$ jruby -S rake SKIP_SPECS=true
warbler のインストール

Rails アプリを Java アプリケーションサーバにデプロイするための gem をインストールします。
*1

$jruby -S gem install warbler
google app engine java sdk をダウンロード

Google 様の言う通りにすると落とせると思います。
appengine-api.jar とデプロイスクリプトを使う。

Rails アプリの作成

Rails インストール

ri や rdoc はファイル数が増えるだけなのでいらない

$jruby -S gem install rails --no-ri --no-rdoc
アプリの作成

コントローラから render :text するだけ

$jruby -S rails hello-gae-gom
$cd hello-gae-gom
$jruby -S script/generate controller index
$vim app/controllers/index_controller.rb

アプリ設定

ルータを設定
$vim config/routes.rb
 map.root :controller => 'index'
protect_from_forgery をコメントアウト

なんだか使えないらしいので、コメントアウト。

$vim app/controllers/apprication_controller.rb
 #protect_from_forgery # See ActionController::RequestForgeryProtection for details
active record は使わない
$vim config/environment.rb
config.frameworks -= [ :active_record]

lib を用意

これまでの手順で作成した jar をまとめて$RAILS_ROOT/lib に入れる

Rails の不要なファイルを削除

rm -rf test/
rm -rf doc/
rm -rf vendor/rails/railties/doc
rm -rf vendor/rails/railties/html
rm -rf vendor/rails/railties/bin
rm -rf vendor/rails/railties/builtin
rm -rf vendor/rails/railties/environments
rm -rf vendor/rails/railties/dispatches
rm -rf vendor/rails/activerecord/
rm -rf vendor/rails/actionmailer/test
rm -rf vendor/rails/actionpack/test
rm -rf vendor/rails/activeresource/test
rm -rf vendor/rails/activesupport/test
rm -rf vendor/rails/railties/test

XML を作成

# appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application>#{app_name}</application>
  <version>2</version>

  <static-files />
  <resource-files />
  <sessions-enabled>true</sessions-enabled>
  <system-properties>
    <property name="jruby.management.enabled" value="false" />
    <property name="os.arch" value="" />
    <property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
    <property name="jruby.compile.fastest" value="true"/>
    <property name="jruby.compile.frameless" value="true"/>
    <property name="jruby.compile.positionless" value="true"/>
    <property name="jruby.compile.threadless" value="false"/>
    <property name="jruby.compile.fastops" value="false"/>
    <property name="jruby.compile.fastcase" value="false"/>
    <property name="jruby.compile.chainsize" value="500"/>
    <property name="jruby.compile.lazyHandles" value="false"/>
    <property name="jruby.compile.peephole" value="true"/>
  </system-properties>
</appengine-web-app>

warble の準備

$jruby -S warble config
$jruby -S warble pluginize
$vim config/warble.rb

Warbler::Config.new do |config|
  config.dirs = %w (app config lib log vendor tmp)
  config.includes = FileList["appengine-web.xml"]
  config.java_libs = []
  config.gem_dependencies = true
  config.webxml.jruby.min.runtimes = 1
  config.webxml.jruby.max.runtimes = 1
  config.webxml.jruby.init.serial = true
end

デプロイ実行

ファイル数のチェック
$find . -type f | wc -l
アップロード
$ appengine-java-sdk/bin/appcfg.sh udpate tmp/war

まとめ

以上、 JRuby on Rails on GAE をやってみました。
Rails2.3.2 以降なら、アプリ作成時にテンプレートを適用することで、作業を簡略化できます。

$jruby -S rails -m template.rb APPNAME

上記で作成したサンプルのアプリとテンプレートを下記に置いてます。
よかったら参考にしてください。
http://github.com/gom/hello-gae-gom/tree/master

追記 2009/04/27 08:20

デモがエラーになっていましたが、再アップしたら直りました。
エラーログにはrackがエラー吐いてたようだけど、今のところ原因がよくわからず。

時間経ってからまた見れなくなってたら、その時にじっくり調べよう。

*1:この gem が何をしてるのかは不明・・・

*2:再確認したが、動かなくなっている。なぜだ。