2012年02月22日

zsh で git を使うときは vcs_info が便利


シェルに zsh を、バージョン管理に git を使う場合、zsh の vcs_info 機能が便利です。これは、バージョン管理システムの情報をコマンドプロンプトに表示できる機能です。

  • 動機(1):gitを使うワークフローでは、頻繁にブランチを作って切り替えるのが普通です。これは優れたワークフローですが、時として現在のブランチが何だったか見失う場合があります。このため、自分が現在どのブランチにいるかを常に把握しておきたいです。
  • 解決(1):現在のブランチをコマンドプロンプトに表示します。


  • 動機(2):gitでは変更をリポジトリに反映する際に、ワーキングコピーからステージングエリアへの反映(git add)、ステージングエリアからローカルリポジトリへの反映(git commit)、ローカルリポジトリからリモートリポジトリへの反映(git push)、と段階があります。これはgitの長所ですが、時としてどれかの処理を忘れるミスが発生してしまいます。このため、現在なんの処理が残っているのかを常に把握しておきたいです。
  • 解決(2):現在の変更の状態(未addがあるか、未commitがあるか、未pushがあるか)をコマンドプロンプトに表示します。


  • 動機(3):gitには変更を一時的に格納しておくstash機能があります。これは便利ですが、時としてstashに入れたまま取り出すのを忘れてしまうミスが発生してしまいます。このため、stashの有無を常に把握しておきたいです。
  • 解決(3):stashの状態をコマンドプロンプトに表示します。


そんなわけで、僕の .zshrc から vcs_info の設定を抜き出して公開してみます。

# vcs_info
autoload vcs_info
# gitのみ有効にする
zstyle ":vcs_info:*" enable git
# commitしていない変更をチェックする
zstyle ":vcs_info:git:*" check-for-changes true
# gitリポジトリに対して、変更情報とリポジトリ情報を表示する
zstyle ":vcs_info:git:*" formats "%c%u[%b:%r]"
# gitリポジトリに対して、コンフリクトなどの情報を表示する
zstyle ":vcs_info:git:*" actionformats "%c%u<%a>[%b:%r]"
# addしていない変更があることを示す文字列
zstyle ":vcs_info:git:*" unstagedstr "<U>"
# commitしていないstageがあることを示す文字列
zstyle ":vcs_info:git:*" stagedstr "<S>"

# git:まだpushしていないcommitあるかチェックする
my_git_info_push () {
if [ "$(git remote 2>/dev/null)" != "" ]; then
local head="$(git rev-parse HEAD)"
local remote
for remote in $(git rev-parse --remotes) ; do
if [ "$head" = "$remote" ]; then return 0 ; fi
done
# pushしていないcommitがあることを示す文字列
echo "<P>"
fi
}

# git:stashに退避したものがあるかチェックする
my_git_info_stash () {
if [ "$(git stash list 2>/dev/null)" != "" ]; then
# stashがあることを示す文字列
echo "{s}"
fi
}

# vcs_infoの出力に独自の出力を付加する
my_vcs_info () {
vcs_info
echo $(my_git_info_stash)$(my_git_info_push)$vcs_info_msg_0_
}

プロンプトは例えば次のように設定します。

# プロンプト定義の中で置換を使用する
setopt prompt_subst

# プロンプト定義
RPROMPT=$'$(my_vcs_info)'

これにより、次のような表示になります。ブランチ名とリポジトリ名が常に表示されます。

% [branch:repository]

また、stashがある、未pushがある、未commitがある、未addがある、という状態では次のような表示になります。

% {s}<P><S><U>[branch:repository]


このおかげで、git が快適に使えています。ありがとう zsh。

補足:

  • 僕は実際にはPROMPTに含めて表示していますが、ここでは簡単に試しやすいRPROMPTを使ってみました。
  • vcs_info機能は様々なバージョン管理システムをサポートしますが、僕はgitのみで使うよう設定しています。


なお、vcs_info の詳細は man zshcontrib に記載があります。最新の zsh だと vcs_info に hook function が追加されているので、my_vcs_info なんて作らずにもう少し美しく書けそうです。
posted by usami-k at 07:00| Comment(0) | TrackBack(0) | 雑文 | このブログの読者になる | 更新情報をチェックする

2011年10月15日

存在しないコマンドを入力したとき、パッケージをインストールするか聞かれる仕組み

Fedora 13 でターミナルを使っているとき、存在しないコマンドを入力すると、パッケージをインストールするか聞かれることがあります。例えば以下のような感じです。


$ sl
コマンドが見つかりません。 コマンド sl' を提供するためにパッケージ 'sl' をインストールしますか? [N/y]


どうやら、コマンドが含まれているパッケージを自動的に教えてくれるようです。ここでリターンを押せばそのまま終了します。また、y を入力してリターンを押すと、その場でパッケージのインストールが始まります。以下のような感じ(途中でrootパスワードを聞かれます)。


$ sl
コマンドが見つかりません。 コマンド sl' を提供するためにパッケージ 'sl' をインストールしますか? [N/y]
* ソフトウェアソースについての詳細をダウンロード中。..
* 実行中..
* 依存関係を解決中..
* 認証を待ち受け中..
* 実行中..
* 依存関係を解決中..
* パッケージをダウンロード中..
* 変更をテスト中..
* パッケージのインストール中..
* アプリケーションをスキャン中..
$


インストールが終わると、自動的にコマンドが実行されます。今回の場合は、sl コマンドが実行されます。

さて、私としては、これがいったいどのような仕組みなのかが気になります。そこで、仕組みを(twitter で何人かの方にヒントをいただきながら)調べました。

実は、Fedora の Wiki にこの機能についての情報が記載されています(調べた後で気づきました・・・)。この記事では、私の調べたことを記載してみます。


コマンドが見つからないと通知するのはシェル(今回の環境では bash)です。bash 4.0 以降には、コマンドが見つからなかったときに実行されるフック関数を指定できます(この機能は、もともと Debian/Ubuntu の独自拡張だったのが、bash 本家に取り込まれたそうです)。

bash で set コマンドを実行すると、command_not_found_handle という関数が見つかりました。これがフック関数で、/etc/profile.d/PackageKit.sh というファイルの中で定義されていました。

command_not_found_handle () {
runcnf=1
retval=127

# don't run if DBus isn't running
[ ! -S /var/run/dbus/system_bus_socket ] && runcnf=0

# don't run if packagekitd doesn't exist in the _system_ root
[ ! -x /usr/libexec/packagekitd ] && runcnf=0

# run the command, or just print a warning
if [ $runcnf -eq 1 ]; then
/usr/libexec/pk-command-not-found $1
retval=$?
else
echo "bash: $1: command not found"
fi

# return success or failure
return $retval
}


このフック関数の中で pk-command-not-found というプログラムが呼ばれます。このソースコードは、PackageKit の contrib ディレクトリに含まれています。この中で PackageKit の機能を使って、コマンドを含むパッケージを探し、インストールするようになっています。

分かってしまえば、わりと単純な仕組みですね。でも、発想が面白い。

なお、この機能は、PackageKit-command-not-found という rpm パッケージがインストールされているときのみ機能します。上記の /etc/profile.d/PackageKit.sh も pk-command-not-found もこのパッケージに含まれています。


$ rpm -qi PackageKit-command-not-found
Name : PackageKit-command-not-found Relocations: (not relocatable)
Version : 0.6.6 Vendor: Fedora Project
Release : 3.fc13 Build Date: 2011年03月25日 18時44分28秒
Install Date: 2011年06月21日 11時45分32秒 Build Host: x86-03.phx2.fedoraproject.org
Group : Development/Libraries Source RPM: PackageKit-0.6.6-3.fc13.src.rpm
Size : 307334 License: GPLv2+ and LGPLv2+
Signature : RSA/SHA256, 2011年03月25日 18時07分04秒, Key ID 7edc6ad6e8e40fde
Packager : Fedora Project
URL : http://www.packagekit.org
Summary : Ask the user to install command line programs automatically
Description :
A simple helper that offers to install new packages on the command line
using PackageKit.
$ rpm -ql PackageKit-command-not-found
/etc/PackageKit/CommandNotFound.conf
/etc/profile.d/PackageKit.sh
/usr/libexec/pk-command-not-found
/usr/share/doc/PackageKit-command-not-found-0.6.6
/usr/share/doc/PackageKit-command-not-found-0.6.6/AUTHORS
/usr/share/doc/PackageKit-command-not-found-0.6.6/COPYING
/usr/share/doc/PackageKit-command-not-found-0.6.6/NEWS
/usr/share/doc/PackageKit-command-not-found-0.6.6/README


最近、久しぶりに Linux を使っていますが、こんな感じで新たな発見があると嬉しくなります。業務上の都合で、ディストリビューションが Fedora 13 固定だったり(ちょっと古いよなあ)、シェルは bash だったり(普段の Mac では zsh なのに)、とかいう制限はあるものの、Linux ってやっぱり楽しい。
posted by usami-k at 13:45| Comment(0) | TrackBack(0) | 雑文 | このブログの読者になる | 更新情報をチェックする

2011年03月25日

Seesaaブログの記事をすべてエクスポートするスクリプト

Sessaaブログには、データのエクスポート機能があって、とても便利だと思います。しかし、少しだけ問題が。

エクスポートの範囲は「すべて」と「月ごと」のいずれかを指定できます。しかし、記事数が多い場合には「すべて」を選択してもエクスポートすることができません。「月ごと」のエクスポートしかできないので、過去何年ものデータを取得しようと思うと、手作業では大変面倒な作業になります。

そこで、すべての記事をエクスポートするRubyスクリプトを作成しました。「月ごと」のエクスポートをすべての月に対して自動実行します。



Mechanizeを初めて使うにあたって、以下のサイトを参考にさせていただきました。解説が分かりやすくて、簡単に目的のスクリプトを書くことができました。感謝します。

RubyのMechanizeを解説 for 1.0.0 - きたももんががきたん。

Ruby Mechanize wiki (ja) - livedoor Wiki(ウィキ)
posted by usami-k at 02:18| Comment(0) | TrackBack(0) | 雑文 | このブログの読者になる | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

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