initial commit 時、.gitignore に追加するべきだったのにその前に staging してしまった。
それらの一部をまとめて unstage
git status | ?{$_.Contains("hoge")} | %{$_.Split() | select -l 1} | %{git rm --cached $_}
説明
一つ目のパイプライン
PowerShell 以外のコマンドから渡されるのはほぼ全て string[]
。
Foreach-Object
や Where-Object
ではこれを1行ずつ処理する。
?
は Where-Object
のエイリアス、 {}
内が true
になったものだけを返す。
$_
は現在のループで回してる 1 オブジェクト。
ここでは string.Contains()
を使って "hoge"
が含まれてる行だけを返してる。
二つ目のパイプライン
%
は Foreach-Object
のエイリアス、 一オブジェクト毎に {}
内を実行する。この場合、 1 行が 1 string。
string.Split()
で 1 行の string をスペース区切り で string[] にしてる。
Split(';')
とかすれば、 セミコロン区切りにできる。何も指定しないとスペース区切り。
今
new
file:
hoge/fuga/foo/bar
という感じになる。
スペースが続いてるところをひとつの区切りとしてくれないので、1個以上のスペースを区切りにしたければ、 $_ -split '\s'+
などと正規表現を使うと良いでしょう。
それで、これをパイプラインで渡す。
3つ目のパイプライン
2つ目のパイプラインの中の Foreach-Object
内でのパイプライン
select
は Select-Object
のエイリアス。
-l
は -Last
を略したもの。PowerShell のパラメーターは一意に決まるだけ書いてあれば問題無い。
つまりパイプラインで渡されたオブジェクトの Last の 1 個を返すので、
上の例で言う hoge/fuga/foo/bar
になる。
4つ目のパイプライン
ここまでで hoge
が含まれている行のパスだけが string として渡されているので、これを最後に git コマンドに渡してあげればよい。
最後に
contains
に渡す文字列を変えて、最後の git コマンドを変えるだけでもいろいろと応用できる。
svn status でもパスは行末にくるので svn にも応用可。
他の例
git status | ?{$_.Contains('modified')} | %{$_.Split() | select -l 1} | %{git checkout -- $_}