cafegale(LeafCage備忘録)

LeafCage備忘録(はてなダイアリー)と統一しました。

Gitの更なるまとめ(書きかけ)

関連エントリ

初期化

SN cmd 説明/引数例
init
cl clone {src_repository} [{dst_path}] https://example.com/path/to/repo.git/ path/to/dir

addからcommitまで

addの反対がreset

SN cmd 説明/引数例
a add {file/dir_pat} ., *.txt(このワイルドカードはシェルの機能), file.txt, dir(dir中身全て追加)
an add -n {file/dir_pat} その{file/dir_pat}で何が追加されるか
au add -u [{file/dir_pat}] ciaのciしない版(管理下にあるものの更新)
ap add -p [{file/dir_pat}] 対話的にadd {file/dir_pat}付与でそれ限定
aa add -A [{file/dir_pat}] 新しく追加・削除・変更された、未管理のファイルを追加
r reset addしたのを全消し
r reset {ver} HEADとindexを過去{ver}の状態に cimのciしない版
rc rm --cached {filepat} {filepat}をindexから消す*1
rp reset -p 対話的にreset
ci commit -v (-vで)変更点を表示しながらコミット
commit -c ORIG_HEAD 前の(rsなどで動かされる前のHEADの)コミットメッセージを再利用してci
cia commit -a auしてci
cim commit --amend rsしてci
ciam commit -a --amend rしてauしてci

状態の確認

SN cmd 説明/引数例
st status -s -b -sシンプルに表示 -bブランチも表示
dh diff HEAD ワークツリーとHEADの差分
d diff ワークツリーとインデックスの差分
dc diff --cached インデックスとHEADの差分(次のciする差分)
lg log リポジトリのログ
ls ls-files 管理中のファイル一覧
rg reflog HEADの遷移

私の使うGitコマンドまとめ 見る編 - Log for Backup - Naoki_Rinの学習

リモート

SN cmd 説明/引数例
roa remote add origin {URL} git@github.com:LeafCage/temp.git
pu push -u origin master 初めてアップロードするときに使う
ro remote -v リモートリポジトリの詳細情報
pf push -f origin {local_blanch:remote_blanch} pf HEAD~:master masterのコミットを取り消す

リポジトリをリネーム

SN cmd 説明/引数例
mv mv {src} {dst}
rc rm --cached {src}, add {dst} すでにリネームしていたとき
rou remote set-url origin {URL} remote originのurlを変更
pd push --delete origin {branch} リモートブランチを削除
pf push -f origin {:remote_blanch} リモートブランチを削除

まだ考えてない

rs reset --soft {ver} ciを取り消し{ver}まで遡る。cimのciしない版に近い。HEAD^

統合

SN cmd 説明/引数例
m merge [--no-ff]{branch} [--no-ff]を付けていないとブランチフラグを動かすだけで統合できるなら新しいリビジョンを作らない
cp cherry-pick {ver} {ver}を取り込む
rb rebase {branch}
rbc add ファイル名→ rebase --continue リベースコンフリクト解消させたことを伝えてrebaseを再会する
rba rebase --abort リベースコンフリクト解消させるのをやめてrebase開始前のworkに戻す

マージのコンフリクト解消

SN cmd 説明/引数例
a add ファイル名 コンフリクトを解消したものとして提出
com checkout --merge ファイル名 コンフリクトを初めからやり直す
coo checkout --ours ファイル名 自分側を一方的に採用
cot git checkout --theirs ファイル名 相手側を一方的に採用

gitでブランチをマージした時にコンフリクトを起こしてしまったら | S4U -smile for you-
【派閥別】Gitのコミットを間違えたときの対処法まとめ - 本当は怖い情報科学

*1:r HEAD -- {filepat}でも同じ効果gitでアレを元に戻す108の方法 - TIM Labs

vim処理速度調査(オートロード関数読み込み編2)

※この記事は全面的に誤っていたので修正されました。
そして、修正後の結果は極めて当然の話なので情報的価値がないです。

ふとruntimeを用いてスクリプトを読み込む場合と、autoload関数呼び出し時のスクリプトのautoloadで速度に違いがあるのか気になったので計測してみた。
速度計測にはLeafCage/laptime.vimを使用した。

autoload

let lt = laptime#new()
call speed1#nop()
call lt.lap()
call speed2#nop()
call lt.lap()
call speed3#nop()
call lt.lap()
call speed4#nop()
call lt.lap()
call speed5#nop()
call lt.lap()
call speed6#nop()
call lt.lap()
call speed7#nop()
call lt.lap()
call speed8#nop()
call lt.lap()
call speed9#nop()
call lt.lap()
call speed10#nop()
call lt.end()
       TOTAL       LAP
  1:   0.003668    0.003668
  2:   0.007119    0.003452
  3:   0.010381    0.003262
  4:   0.013674    0.003293
  5:   0.017192    0.003517
  6:   0.020612    0.003421
  7:   0.025109    0.004497
  8:   0.028710    0.003600
  9:   0.032110    0.003400
 10:   0.037759    0.005649

runtime

let lt = laptime#new()
runtime autoload/speed1.vim
call lt.lap()
runtime autoload/speed2.vim
call lt.lap()
runtime autoload/speed3.vim
call lt.lap()
runtime autoload/speed4.vim
call lt.lap()
runtime autoload/speed5.vim
call lt.lap()
runtime autoload/speed6.vim
call lt.lap()
runtime autoload/speed7.vim
call lt.lap()
runtime autoload/speed8.vim
call lt.lap()
runtime autoload/speed9.vim
call lt.lap()
runtime autoload/speed10.vim
call lt.end()
       TOTAL       LAP
  1:   0.007248    0.007248
  2:   0.013605    0.006357
  3:   0.019803    0.006198
  4:   0.027628    0.007826
  5:   0.034176    0.006548
  6:   0.040779    0.006603
  7:   0.046969    0.006190
  8:   0.053571    0.006602
  9:   0.060535    0.006964
 10:   0.067262    0.006728

2度読み込みされている分、:runtime のほうが遅かったです

vim処理速度調査(オートロード関数読み込み編)

以下の内容が書かれたファイルをautoload/speed1.vimとして置く。

function! speed1#nop()
endfunction

同様に、autoload/speed1.vim、autoload/speed2.vim、...としてautoload/speed10.vimまで同様に置く。

そして、以下のスクリプトを:sourceする。
速度計測にはLeafCage/laptime.vimを使用する。

let lt = laptime#new()
call speed1#nop()
call lt.lap()
call speed2#nop()
call lt.lap()
call speed3#nop()
call lt.lap()
call speed4#nop()
call lt.lap()
call speed5#nop()
call lt.lap()
call speed6#nop()
call lt.lap()
call speed7#nop()
call lt.lap()
call speed8#nop()
call lt.lap()
call speed9#nop()
call lt.lap()
call speed10#nop()
call lt.end()

結果は以下のとおり

       TOTAL       LAP
  1:   0.003770    0.003770
  2:   0.007049    0.003279
  3:   0.010308    0.003259
  4:   0.013501    0.003194
  5:   0.017289    0.003788
  6:   0.021382    0.004093
  7:   0.024573    0.003191
  8:   0.027727    0.003153
  9:   0.030940    0.003213
 10:   0.034118    0.003179  

内容の(ほとんどない)ない10のファイルを読み込むだけで計約0.034秒かかっている。

いったい何が原因なのか?
なぜ(ほとんど)空っぽのファイルをsourceするのにここまで時間がかかっているのか?
Vimはautoload関数が呼ばれるとruntimepathから該当ファイルを探してsourceするが、もしやここで時間がかかっているのかもしれない。
私はneobundle.vimプラグインを管理しているが、その代償としてruntimepathに複数のパスが設定されている。
私のVim起動直後のruntimepathは以下のとおりであった。

runtimepath=~/vimfiles,~/box/vimfiles/neobundle/vim-fugitive,~/box/vimfiles/neobundle/vimproc,~/box/vimfiles/neobundle/tlib_vim,~/box/vim
files/neobundle/vital.vim,~/box/vimfiles/neobundle/vim-openbuf,~/box/vimfiles/neobundle/curses-vim,~/box/vimfiles/neobundle/vim-submode,~/b
ox/vimfiles/neobundle/vim-altr,~/box/vimfiles/neobundle/mdv,~/box/vimfiles/neobundle/vimhelpgenerator,~/box/vimfiles/neobundle/laptime.vim,
~/box/vimfiles/neobundle/neocomplcache,~/box/vimfiles/neobundle/neosnippet,~/box/vimfiles/neobundle/vim-operator-user,~/box/vimfiles/neobun
dle/vim-textobj-user,~/box/vimfiles/neobundle/textobj-wiw,~/box/vimfiles/neobundle/vim-textobj-indent,~/box/vimfiles/neobundle/vim-textobj-
plugins,~/box/vimfiles/neobundle/vim-textobj-xbrackets,~/box/vimfiles/neobundle/vim-textobj-parameter,~/box/vimfiles/neobundle/nerdcommente
r,~/box/vimfiles/neobundle/ToggleCase-vim,~/box/vimfiles/neobundle/jasegment.vim,~/box/vimfiles/neobundle/clever-f.vim,~/box/vimfiles/neobu
ndle/vim-ambicmd,~/box/vimfiles/neobundle/vim-altercmd,~/box/vim

そこで今度は:set rtp=~/vimfilesとして、runtimepathのパスを一つだけにしてから同じことをやってみた。

       TOTAL       LAP
  1:   0.001546    0.001546
  2:   0.002974    0.001428
  3:   0.004392    0.001418
  4:   0.005837    0.001445
  5:   0.007338    0.001501
  6:   0.008639    0.001301
  7:   0.009950    0.001311
  8:   0.011222    0.001271
  9:   0.012507    0.001286
 10:   0.014164    0.001656

処理時間が目に見えて短くなった(半分以下に)。すなわち時間がかかっている原因は、一つは探索場所が広大だったせいである。
だが、ちょっと待ってほしい。
確かに0.0015秒と短くなったとはいえ、これでもVimの処理の中では時間がかかってるほうである。拙作のプラグインにlaptime.vimというのがあるが、その関数の一つ、s:lt.end()のリストの要素が10個のときと同じくらいの時間がかかっている(これの実行時間は約0.0016秒)。

これはそれなりにリスト処理や文字列処理を含んでいる。つまりruntimepathを1つにして、探索場所を減らした状態でも、それなりの処理を含む1つの関数くらいの時間はかかっているわけである。

ちなみに、call speed1#nop()などの関数はほとんど何の仕事もしていないのであるが、これ自体の処理時間はおよそ0.0001秒である。二度目の関数呼び出しからはsourceの時間がなくなるので、この関数の時間だけしかかからず処理が高速になる。


参考

let s:test = range(101)
call filter(s:test, 'v:val != "0"')

↑の処理時間は約0.0019秒前後

let s:test = range(101)
call map(s:test, 'v:val. "yen"')
call match(s:test, '25yen')

約0.002秒

let s:test = range(101)
call map(s:test, 'v:val. "yen"')
call filter(s:test, 'v:val != "0yen"')

約0.0039秒前後

vim処理速度調査(関数呼び出しin オートロード変数)

この問題はそれとして、現行の回避策として、以下の4通りの方法がある。

  • eval()で評価
  • type()で評価
  • :silent letで呼び出し
  • :silent echoで呼び出し

それぞれの呼び出し速度を比較して、もっとも短く呼び出せる方式を採用することにする。
結果。

eval()
0.003490
0.003302
0.003400

type()
0.003586
0.004332

silent let
0.003543
0.003593
0.003495

silent echo
0.004006
0.004823

明らかにeval()が速かった。見た目的にも一番素直だし、eval()を採用することにする。

Vimプラグインを作るときにはautoload以下のファイルをあまり分割すべきでない

理由はVimの実行速度が遅いから。
おそらく2000行の1つのスクリプトファイルを読み込むよりも、100行の2つのスクリプトを読み込むほうが速度が遅い。なぜなら、該当ファイルを探すのに結構な時間がかかるからである。

(追記:その後、検証して、やはりautoloadスクリプトを1つ探して読み込むのに結構な時間を費やすことが分かった。autoload関数(オートロードスクリプト)の初回読み込みが遅い · Issue #461 · vim-jp/issues)


もちろん、plugin以下の記述は少なくしてその分をautoload以下に移すのは大いに推奨される。
起動時には大量のスクリプトが読まれるので少しでも記述は少なくしておいたほうが起動が早い。

しかしプラグインが実行され、autoload以下が読まれるときに、初回時に必ず読まれる部分は、分割すると、ファイル探索のオーバーヘッドが入る分、遅くなるだけなので出来る限り少数の、出来れば単一のファイルにしておくべきである。
そもそも:sourceするのに時間は余りかからない。さっき言ったとおりファイルを探し出すことのほうがはるかに時間がかかる。
ましてvitalなどのライブラリを使っているプラグインでは、ライブラリの読み込みで余計にファイルを読み込ませているので、そこにさらにスクリプトの分割なんてするとさらなる速度低下を引き起こし、読み込みの遅さが体感レベルに達することになる。

もちろん、一度に読み込むところでないのなら、スクリプトをさらに分割しても問題ない。

Vimプラグインのヘルプドキュメントを自動生成する

この記事はVim Advent Calendar 2012 : ATND 257日目の記事です。


皆さんVimプラグインを作ったことはありますか?
VACではプラグインを書いて公開するまでにやることについての記事がいくつかあります。

プラグインを作ったら、doc/以下にヘルプドキュメントを添付します。
そうすることで、:helpでいつでもドキュメントを参照することが出来ます。
ヘルプを添付しないと神様に叱られてしまいます

しかしながら、ヘルプを書くのはプラグインを作る中でももっとも苦痛な作業のひとつです*1
かく言う私もヘルプ不精で、ヘルプを添付せず、ソースの中に使い方を書いたコメントを書くことや、ブログの記事での紹介で済ませてしまっていることが多々あります。

だから作りました。

プラグインのヘルプを自動的に作成するプラグインです。

初期設定

以下の変数を.vimrcなどに定義します。

g:vimhelpgenerator_defaultlanguage
"ja"を指定すると日本語、"en"を指定すると英語のヘルプを作成する。
g:vimhelpgenerator_version
"Version :"の項に表示される文字列。空文字で無効。
g:vimhelpgenerator_author
"Author :"の項に表示される文字列。空文字で無効。
g:vimhelpgenerator_license
表示するライセンスを記述したファイルの&runtimepath以下のパスを記述。既定はMIT license(変更再配布OKだけど、どこかに著作者名の記述義務)。ほかにzlib/libpng(ソース形式で配布するなら著作者名の記述義務)、NYSL(著作者名の記述の義務すらなし。)のファイルがvimhelpgenerator/以下に用意されている。空文字や読めないファイル名を指定すると無効。※
g:vimhelpgenerator_contents
表示させるコンテンツを指定する辞書。0にしたコンテンツは表示されない。1より上の数を指定することでコンテンツの表示順を並べ替えることが出来る(若い数ほど先に表示される)。

設定例

let g:vimhelpgenerator_version = ''
let g:vimhelpgenerator_author = 'Author  : LeafCage <leafcage+vim @ gmail.com>'
let g:vimhelpgenerator_contents = {
  \ 'contents': 1, 'introduction': 1, 'usage': 1, 'interface': 1,
  \ 'variables': 1, 'commands': 1, 'key-mappings': 1, 'functions': 1,
  \ 'setting': 0, 'todo': 1, 'changelog': 0
  \ }

使い方

まずはヘルプを作成したいプラグインのいずれかのファイルを開きます。
f:id:leafcage:20130817131015p:plain


次に、:VimHelpGeneratorコマンドを実行します。
f:id:leafcage:20130817131042p:plain


ヘルプを作成するプラグインのパスと名前を確認してくるので、間違いなければeを入力して実行します。
f:id:leafcage:20130817131056p:plain


生成されたヘルプが開かれます*2
フォーマットは日本人プラグイン開発者の多くが使っているものを参考にしました。
(もしも日本語でヘルプを作るのなら、第一行目にマルチバイト文字を含んでください。そうしないと:helptagsしたときエラーE670が出ます。)
f:id:leafcage:20130817131358p:plain


概要や使い方は皆様の手で書くことが出来ます。
f:id:leafcage:20130817131406p:plain


変数や関数、コマンドやキーマップは、自動収集されたもので埋められます。
グローバルなものは何でも取ってくるので、公開したくないものは削除してください。
また、精度が良くないので、間違っている部分があれば修正してください(特に変数について辞書は既定値が取得できません。既定値の取得は結構いい加減です)。
それぞれの説明文は人力で埋めてください。
f:id:leafcage:20130817131417p:plain


これで随分とヘルプを作るのが楽になったはずです。
これからはヘルプ無しのプラグインを作るなんてあり得ませんね!

実は

申し訳程度に、ヘルプの出力を全面的にカスタマイズする機構も用意しています。詳しくはhelpをご覧ください。

新しいバージョンのVimでは上手く動いていませんでした。現在は動作するはずです。問題点を発見すればIssues · LeafCage/vimhelpgeneratorへ報告をお願いします。

*1:詳細なヘルプを毎回添付している先人たちには敬服します。

*2:このとき密かに.gitignoreとREADME.mdも出力していました。:HelpIntoMarkdownコマンドが導入されたのでREADME.mdの出力はオミットされました