gitメモ:ブランチを切ってないのにやばいコードを書いちゃった場

2010年7月30日 09:32

 gitを使ってコードの管理をしている場合において、実験的なコードを書く場合はソースコードを編集する前にブランチを作成しておくのが基本だ。しかし、ついブランチを作成し忘れたままでコードを変更してしまった、というパターンがある。

 この場合、下記のようにgit stashでいったん変更点を保存した上で直前のcommitに戻し、新たなブランチを作成してそこでgit stash applyを行えばよい。

$ git stash
$ git checkout hogehoge -b
$ git stash apply
$ git add hogehoge foobar
$ git commit

 git stash、便利だ。

Small Basic 0.9リリース

2010年6月14日 13:20

 Microsoftがプログラミング学習用としてリリースしているBASICプログラミング環境「Small Basic」の0.9が6月11日にリリースされた。

 Small Basicブログによると、Small Basicコンパイラのパフォーマンス強化や新規ライブラリの追加などが行われているとのこと。ループが多いプログラムで、4倍ものパフォーマンス向上を達成できた例もあるそうだ。

 追加されたライブラリでは、MML的記法で音楽を再生できる「PlayMusic」機能が面白そうだ。教育用とはいえ、Flickr連携や作成したプログラムをSilverlightを用いてWebブラウザ上で実行する機能などもあり、ちょっとしたユーティリティなどを作成するのにも便利かもしれない。

Pythonのwith構文と__enter__、__exit__

2010年5月18日 20:27

 Pythonのwith構文がいまいち掴めなかったので、ざっとまとめてみた(いまさらながら)。ドキュメントはPython リファレンスマニュアルの7.5 with 文にある。

 withを使ったコード例は、下記のような感じ。

c = ClassHogeHoge()
with c:
    c.foobar()

 上記のコードは、下記と等価となる。

c = ClassHogeHoge()
c.__enter__()
c.foobar()
c.__exit__()

 つまり、withに続くインデントブロックを実行する前に指定したオブジェクトの「__enter__()」メソッドを呼び出し、実行後に「__exit__()」メソッドが暗に呼び出される、という仕組み。

 __enter__()と__exit__()の定義は、Python リファレンスマニュアルの3.4.9 with文とコンテキストマネージャにある。__enter__()の引数はselfのみだが、__exit__()はself、exc_type、exc_value、tracebackの4つの引数をとる。withに続くインデントブロックが正常に実行された(つまり、例外が送出されなかった)場合、(self以外の)引数にはNoneが与えられる。なにか例外が発生した場合、その例外に関する情報が与えられるらしい。

 また、「with hogehoge as foo:」のような形でwith文を利用する場合、__enter__()の戻り値がfooに代入される。__exit__()の戻り値は例外処理の伝搬制御に使われ、Falseの場合例外が発生た場合でも例外を伝搬させず、Trueを返すと例外が伝搬されるとのこと。

 下記、使用例。

class CacheDB(object):
    DB_FILE = "database/db_dat"

    def __init__(self):
        self.con = None
        self.cur = None

    def __enter__(self):
        self.con = sqlite3.connect(self.DB_FILE)
        self.cur = self.con.cursor()

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type:
            self.con = None
            self.cur = None
            return False
        self.con.commit()
        self.cur.close()
        self.con.close()
        self.con = None
        self.cur = None
        return True

    def add(self, foo, bar, hoge):
        try:
            self.cur.execute("""insert into data ( foo, bar, hoge )
                           values (?, ?, ?);""", (foo, bar, hoge))

def main():
    usage = "%s logfile" % sys.argv[0]
    db = CacheDB()
    try:
        fname = args[0]
    except IndexError:
        sys.exit(usage)

    f = open(fname, "r")
    with db:
        for l in f:
            term = l.strip().decode("utf-8").rsplit("\t", 3)
            db.add(foo=term[0],
                   bar=term[1],
                   hoge=term[2])

if __name__ == '__main__':
    main()

 タブ区切りのデータファイルを1行ずつ読んでデータベースに突込む、という処理。withを使うことで、データベースアクセスの準備→データ挿入→コミットという流れをきれいに実装できました。

Mako Templaters for Pythonメモ1:Makoってなに?

2010年2月2日 15:32

 最近Pythonのテンプレートエンジン「Mako」を触ってるんだけど、日本語の情報が全然ないのでまとめてみる。

Mako公式Webサイト

Mako公式Webサイト

gitメモ:diffとやり直し

2009年12月2日 15:33

 最近久しぶりにgitを触って色々と忘れていたので再度メモ。

mergeを取り消す

 mergeを実行したらconflictが大量に出てしまったので取り消したい、という場合、下記を実行。

$ git reset --hard ORIG_HEAD

conflictを解決する

 gitにはmergeを実行した場合にconflictを解決するコマンド「git mergetool」がある。conflictしているファイルに対して、順番にdiffツールを実行して編集を促すもの。しかし、Windows上のMSysGit環境で実行したら見事にvimのdiffが実行されたので個人的にはデフォルトでは使えない認定(自分はvimはあまり使えないので)。

$ git mergetool

 .gitconfigの「merge」および「mergetool」項目で起動するツールを設定できるそうなので、今度はEmacsに設定してテストしてみようかな。

diffを使う

 マニュアルに書いてあるけど、「git diff」コマンドの書式は下記のとおり。

git diff <比較元commit> <比較先commit> [<対象ファイルパス>]

 ここで、比較元・比較先commitはハッシュだけでなく、「HEAD」(最新のコミット)や「HEAD^」(最新の1つ前のコミット)、「HEAD^^」(最新の2つ前のコミット)、「HEAD~4」(最新の4つ前のコミット)などのほか、tagも利用可能。

 例えば最新のコミットと、その1つ前のコミットでdiffを取るには次のようにする。

$ git diff HEAD^ HEAD hogehoge.py