実行できるスクリプトを作成したいと思います。
git diff --name-status master..<BRANCH>
しかし、私がこれを実行した場合:
for i in $(git branch | grep -v master); do
echo $i;
done
エコーアスタリスクのため、ディレクトリはエコーされますgit branch
(現在のディレクトリにディレクトリがあります)。
* <SELECTED BRANCH>
*
拡張される理由とそれを防ぐ方法は何ですか?
修正する:以下を使用してこれを防ぐことができます。
for i in $(git branch | tr -d '*' | grep -v master);
done;
しかし、なぜこれが起こるのですか?スターを削除するのはなぜですか?
答え1
引用符のない変数やコマンドの置換(例:$i
または$(git …)
適用)分割+グローバル演算子文字列の結果に。それは:
- 変数値またはコマンド出力を含む文字列を設定します(後者の場合は最後の改行を除く)。
- 値に応じて文字列を別のフィールドに分割
IFS
。 - 各フィールドをワイルドカードパターンとして解釈し、それを一致するファイル名のリストに置き換えます。パターンが一致するファイルがない場合は、そのままにしておきます。
git branch | grep -v master
出力内容(ステップ1)は* master
2つのフィールドに分割(ステップ2)され*
(ステップ3)、現在のディレクトリのファイル名のリストmaster
に置き換えられます。*
ワイルドカードを一時的に無効にするために実行できますset -f
。別のアプローチはコマンドの置換を避け、代わりに入力の解析read
。しかし、どちらも正しいことではありません。 git出力に必要なものよりも多くの内容が含まれているため、偽のブランチ名を取得します(*
現在のブランチを表すフラグだけでなく、remotes/somewhere/foo -> bar
リモートトレースブランチなども含みます)。優雅ではなくても、次は安全だと思います。
for i in $(git branch | sed -e 's/^..//' -e 's/ .*//'); do
echo $i
done
最も信頼できる方法は次のとおりです。git-for-each-ref
。
for i in $(git for-each-ref --format='%(refname:short)' refs/heads refs/remotes); do
echo $i
done
答え2
while
このようなテキストストリームは、ループではなくループを使用して読み取る必要があります。for
、これは問題を引き起こす可能性があります(再現することはできませんが)。これを行う簡単な方法は次のとおりです。
git branch | while IFS= read -r line
do
echo "${line:2}"
done
比較する:
$ cd -- "$(mktemp -d)"
$ git init
Initialized empty Git repository in /tmp/tmp.MJFmu7q7EH/.git/
$ touch README
$ git commit --allow-empty -m "Initial commit"
[master (root-commit) da46b03] Initial commit
$ git branch foo
$ git branch
foo
* master
$ for i in $(git branch)
> do
> echo $i
> done
foo
*
master
$ git branch | while IFS= read -r line
> do
> echo "${line:2}"
> done
foo
master