问题
Most advanced uses of git for-each-ref
that I've come across involve eval
. For instance, the last example in the git-for-each-ref man page uses eval
in order to execute the contents of the fmt
variable:
#!/bin/sh
fmt='
r=%(refname)
# ... omitted, for conciseness ...
'
eval=`git for-each-ref --shell --format="$fmt" \
# ... omitted, for conciseness ...
refs/tags`
eval "$eval"
However, the use of eval is associated with security risks; avoiding it, whenever possible, is considered good practice.
Here is a real example, adapted from this answer:
#!/bin/sh
fmt='
ref=%(refname:short)
if git merge-base --is-ancestor $1 $ref; then
printf "%s\n" "$ref"
fi
'
eval "$(git for-each-ref --shell --format="$fmt" refs/heads/)"
In this particular example, how can I avoid using eval
? I've reviewed the options listed in Zenexer's answer, but I couldn't find one that does the trick. I'm looking for as portable (across different shells) a solution as possible.
回答1:
Instead of treating data as code using eval
, you let git for-each-ref
output a stream of data in a format that is easy for you to process. Then, you write a custom processor for that data.
git for-each-ref --format "<values>" \
# more options
refs/tags | while read refname object_type <more args> ; do
<code>
done
As for the specific example you gave, here is an equivalent non-eval version:
#!/bin/bash
if [ $# -ne 1 ]; then
printf "usage: git branchesthatcontain <rev>\n\n"
exit 1
fi
rev=$1
git for-each-ref --format='%(refname:short)' refs/heads \
| while read ref; do
if git merge-base --is-ancestor "$rev" "$ref"; then
echo "$ref"
fi;
done
exit $?
I must add that git-for-each-ref
does include --shell
, --python
and --tcl
flags which ensures that the data is properly escaped: this is not the same scenario as in the accepted answer to the question you reference.
This question and the associated answer are also relevant.
来源:https://stackoverflow.com/questions/31875496/how-can-i-avoid-using-eval-in-conjunction-with-git-for-each-ref