こんな感じです。
概要
Git管理下で作業していると開発に夢中になって、気付いたらワーキングディレクトリがたくさんのファイルで溢れている!
という状況にしばしば陥るときはありませんか?
ここで思い出すんです。。。
(commitの粒度は小さくしないと怒られる!!)
そこで僕はいつも git diff
で差分見て、良い感じに git add
して git commit
しているんですけど、
これがまた面倒臭い作業でして、もっと楽にできないのか!と思い、fzfで選択的対話的にdiff add
できるスクリプトを書きました。
(注:そうなる前に都度コミットするように気を付けましょう)
環境
- Mac OSX El Capitan 10.11.5
- Zsh 5.2
- fzf
fzfは選択的インターフェースで曖昧検索ができるコマンドです。
スクリプト
fadd() {
local out q n addfiles
while out=$(
git status --short |
awk '{if (substr($0,2,1) !~ / /) print $2}' |
fzf-tmux --multi --exit-0 --expect=ctrl-d); do
q=$(head -1 <<< "$out")
n=$[$(wc -l <<< "$out") - 1]
addfiles=(`echo $(tail "-$n" <<< "$out")`)
[[ -z "$addfiles" ]] && continue
if [ "$q" = ctrl-d ]; then
git diff --color=always $addfiles | less -R
else
git add $addfiles
fi
done
}
ざっくり言うと
git status
でunstaged or untrackedなものを fzf に渡して
-
Ctrl-d
でdiff
-
Enter
でadd
しています。
シェルスクリプト初心者なので間違いがあるかもしれませんが、一応ソースコードを追って説明します。
ローカル変数
- out (fzfからの出力)
- q (コマンド)
- n (複数選択の場合のファイル数)
- addfiles (実際にaddするファイル)
git status --short
これは [XY] [path] という形式で、
Xがステージされたもので、Yがステージされていないものです。
$ git status --short
M .vimrc # modifiedでunstaged
M .zshrc # modifiedでstaged
?? newfile # untracked
A sample.rb # new fileでstaged
わかりにくいですね^^;
他にもあるので詳しくはGitのdocsを見て下さい。
awk
awk '{if (substr($0,2,1) !~ / /) print $2}'
先程のgit status --short
から1行ずつ受取り、
status[XY]のうち、Yがブランクでないという条件で、unstaged, untrackedなファイルを判別し、
2列目(ファイルパス)をfzfに渡します。
fzf
--expectオプションで、ファイル選択のデフォルトキーであるEnterの代わりにCtrl-dで選択可能にしています。
そして、ローカル変数 out に コマンド、ファイル、、、、(--multiによりCtrl-iで複数選択可)と格納されます。
あとは、qにコマンドを(Ctrl-d or Enter)
nにファイル数を
addfilesにファイルを入れて
Ctrl-d -> git diff
Enter -> git add
としています。
最後の方雑になってしまいました。。。
何か、問題点や改善点がありましたらコメントして頂けると幸いです!!
githubでdotfiles管理しているので宜しければご覧になってください^^
https://github.com/yuuuuuki/dotfiles