git ls-filesはディレクトリを指定してもそのディレクトリ以下のすべての管理されているファイルを表示します。
シェルで使うlsの様にカレントディレクトリだけを表示したい時はちょっと工夫がいります。
また、ignoreされているファイルやファイルの状態も見たい、ということで それを実現するaliasについて。
現在のディレクトリで管理されているファイルのみを表示
how to
git ls-filesfor just one directory level. - Stack Overflow
上にある答えを使って
1
| |
とすれば現在のディレクトリで管理されているファイルのみを表示できます。
一番簡易にはこれで足りることが多いかと思います。
変更したあとに細かく見ようと思うとこれだとチョット足りません。
ls-filesには-tといった状態を示すオプションもありますが、
これは引数の状態に合わせて表示されるだけで、
通常のls-filesであれば全てH(tracked file that is not either unmerged or skip-worktree)になります。
変更が入っているファイルだけを表示したければ
git ls-files -m -tとかするとCと表示され、変更されたものでstagingされてないものだけが表示されます。
ただ、stagedな状態でmodifiedとかの状態はわからないので全て何もしてないファイルと同等に見えてしまいます。
管理されてるディレクトリのみ表示
How to git list only the tracked directories? - Stack Overflow
上の最初の答えでは
1
| |
となってますが、これだとdirnameなので下に多階層のディレクトリ構造があると上手くいきません。
直接cut -d '/' -f1とかで良さそう。
そのままやるとカレントディレクトリのファイルも/を含まないですがそのまま表示されてしまうので
1
| |
とすれば必要なものが取得できます。
加えて、各ディレクトリの中に変更があるかどうかも見たい時、git statusの結果を見て
1 2 3 4 5 6 7 8 9 | |
のように変更があるとstagedとunstagedでそれぞれで、
staged:Changes to be committed:unstaged:Changes not staged for commit:
といった出力があります。
これを各ディレクトリ毎に見て、
以下で見るgit status -sの表記と同じになるように
1 2 3 4 5 | |
と、それぞれ何らか変更があればM、なければスペースを表示するようにできます。
最近の通常のシェルスクリプトなら
1 2 3 | |
のように書くことも可能で、こちらのほうがサブシェルに入らないので色々便利ですが、 この書き方はgitの中のシェルが理解してくれないのでaliasを書く際には上のようなパイプで繋いだ形でやる必要があります。
変更されたファイル、ignoreされたファイルの表示
git status -sで現在のレポジトリ内の変更があったファイルに関して、staged, unstaged両方の状態を簡単に見ることができます。
1 2 3 | |
とかならaは変更された後git addされている状態、bは変更されたけどgit addされていない状態です。
また、git mvでrenameな状態にあると、
1 2 | |
みたいな感じで表示されます。
さらに--ignoredオプションを加えると.gitignoreで指定されている除外ファイルも
1
| |
のように!!な状態として表示されます。
このgit stagusでもls-files同様に:(glob)*を渡すことで現在のディレクトリのみを見ることが可能です。
ただし、1つだけとれないのが別のディレクトリからrenameされてきたもの。
cというファイルが他のディレクトリからgit mvで持ってこられるとそのままだと
1 2 | |
の様にrenameしたことがわかりますが、元のファイルのディレクトリを除いた範囲で見てみると
1 2 | |
と、単に新しく加えられたファイルのように見えてしまいます。
このrenameもきちんと捉えるためと、カレントディレクトリ中でignore、及びまだ追加されていないディレクトリ
も含めて取得するために以下のようなスクリプトを考えます。
1 2 3 4 5 6 7 8 9 10 11 12 | |
こんな感じに、git statusでは全て表示させ、2列目とrenameがあった場合の4列目
を見てそれが/を含まない、つまりカレントディレクトリのものであれば見るようなことができます。
while IFS=と区切り文字を変更しているのは出力の最初にスペースがある可能性があるので、
元のIFSのままだとそこが消されてしまうのでそれを防ぐためにIFS=として区切り文字をなくすことで
行ごとにそのまま扱うことができます。
また、各行でもgit status -sだと最初にスペースがあるかないか、1列目と2列目で区切りがスペース1個か2個か分かれますが、
echo $lineでquoteしないと最初のスペースは消され、文字列中のスペースが複数あっても全て1つにまとまるので
後ろで簡単にcutで区切れます。
スクリプトではまずstatusを表示されたファイル(及びディレクトリ)とそれがrenameされたものの場合にはrename先の名前を取得します。
最初のif文はそのどちらもがカレントディレクトリよい上のディレクトリにある場合にskipするもの(../でスタートするものを除く)。
次のif文ではスラッシュが含まれないカレントディレクトリのファイル、及び最後がスラッシュになっているカレントディレクトリにあるディレクトリのみを抜き出して表示しています。
これに引っかからなかった時、rename先のファイルがあり、それがカレントディレクトリのファイルであれば表示しています。
空のディレクトリの検出
空のディレクトリはgitの管理下にはなりませんが、ignoreされてるわけでもunstagedな状態にあるわけでもありません。
なので上の作業では一切出てきませんが、とりあえずカレントディレクトリにあるディレクトリをパット表示するには
1
| |
こんな感じで。
.gitディレクトリだけは手動で外します。
aliasにまとめる
ファイルを表示する
git ls-files ':(glob)*'には変更があってgit statusに表示されるものも含まれるので、
まずgit statusから一覧を作り、その中にないものでls-filesで見つかったファイルを追加します。
git statusではディレクトリはignoreされているもの、まだ追加されていないもののみが表示されるため、
git ls-filesでは表示されません。
したがって上で作ったstatus込のディレクトリはそのまま追加します。
これを.gitconfigの[alias]欄に追加出来る様に書き直すと
1 2 3 4 5 6 7 8 9 | |
こんな感じに。
while文はパイプを使う形にしているので中で変数を変更しても後で使えないため、echoとかの出力を外側で変数に入れる必要がありますが、
これをするためにワンライナーにして$()の中に突っ込んで、filesという変数の中に入れています。
最初にgit statusの結果。
次にgit ls-filesでカレントディレクトリのファイルを追加。
ここではfilesをまず表示して、その中に無いものだけを選ぶようにfilesの出力からawk '{print $2}、及びawk '{print $4}'で
ファイル部分、rename先を取得してそれらとの比較などを行って重複を除いています。
次にgit ls-filesを使ってカレントディレクトリないの管理されているディレクトリの追加。
最後に空のディレクトリの追加。ここではgit ls-filesの結果で最初のstatusが全部空のものもあるので直接awkではなくcut -c 4- | print '{print $1}'で文字位置を見て抜き出すようなことをしています。
一番最後はファイル名の部分でソートして出力です。(2文字のstatus, 1文字のスペースがあるので、1番目のfield位置、つまり先頭から4文字目以降でソートする。)
もうちょっときれいな書き方も出来るかもしれませんがとりあえずこれで、
1
| |
とすることで現在のディレクトリのファイルの状態をぱっと見ることができます。
以下のようなテストレポジトリで見てみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |
git ls-hereすると
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |