Edited at

PowerShell を使った、 git のまとめて unstage

More than 1 year has passed since last update.

initial commit 時、.gitignore に追加するべきだったのにその前に staging してしまった。

それらの一部をまとめて unstage

git status | ?{$_.Contains("hoge")} | %{$_.Split() | select -l 1} | %{git rm --cached $_}


説明


一つ目のパイプライン

PowerShell 以外のコマンドから渡されるのはほぼ全て string[]

Foreach-ObjectWhere-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 内でのパイプライン

selectSelect-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 -- $_}