我有一个简单的GIT脚本:
cp --parents $(git diff --name-only $1 $2) $3
git diff ...
- 在提交之间获取修改的文件列表($ 1和$ 2)。
cp --parents ...
- 将它们复制到所需目录($ 3)。
但唯一的问题是:目录名称中有空格。在这种情况下,脚本无法正常工作。显然,git diff
输出的每一行都应该用引号括起来,但是如何?
还是有另一种解决方案吗?找不到它。
答案 0 :(得分:4)
git diff
支持-z
选项,该选项将NUL分隔名称。然后,您可以通过xargs
进行管道传输。例如:
$ git diff -z --name-only HEAD^ HEAD | xargs -I% -0 cp --parents "%" /tmp/
xargs
的选项:
-0
导致它期望输入数据被NUL分隔; -I%
使每个输入运行一次命令,并在命令行中用输入替换%
(在Windows上显然是-i%
?)。 %
被任意选择,因为它很短,您也可以使用-IFOO
/ "FOO"
; cp ...
要执行的命令。我使用/tmp/
作为安全示例。
所以这应该有效地运行
$ cp --parents "file1" /tmp/
等等。或者,您可以在Bash中逐行读取git diff
的输出。
$ git diff --name-only HEAD^ HEAD | ( while read fn ; do cp "${fn}" /tmp/ ; done )
答案 1 :(得分:2)
让我们在这里偏执,并以一种即使对非常不寻常/可能有恶意的文件名也有效的方式这样做:
while IFS= read -r -d '' filename; do
cp --parents -- "$fn" /tmp/
done < <(git diff -z --name-only -- "$1" "$2")
IFS= read
)可防止名称中的尾随空格被剥离。-r
参数read
可以防止文件名中的文字反斜杠被删除,从而被剥离。diff -z
和read -d ''
NUL分隔名称; NUL是POSIX文件名中唯一不存在的字符。--
使cp
将文件名视为文件名,即使它们以-
字符开头,否则将被视为选项。同样适用于git diff
。< <(...)
构造而不是将while
循环放在管道的右侧意味着如果您愿意,可以在循环内设置变量,这些变量仍然会以后存在。有人发现某些版本的msys运行时环境(特别是包含Windows的“git bash”附带的版本)不支持进程替换。因此,可能有必要使用管道(包含所有caveats this implies):
git diff -z --name-only -- "$1" "$2" |
while IFS= read -r -d '' filename; do
cp --parents -- "$fn" /tmp/
done