如何从git status中提取变更或新增的目录名称?
获取Git变更文件的所有层级父目录列表
没问题,完全可以通过Git结合一些Shell命令来实现这个需求——提取所有变更文件的所有层级父目录(比如stack/newstack/test/test11.txt会输出stack/newstack/test、stack/newstack、stack),不管是新增的目录还是包含变更文件的目录都能覆盖到。
方法1:基于git status的一站式处理
这个方法直接从git status的输出入手,处理所有变更(已暂存、未暂存、未跟踪)的文件和目录:
git status -s -uall | awk '{print $2}' | while read path; do # 去掉目录路径末尾的斜杠,避免后续处理出错 if [[ "$path" == */ ]]; then path="${path%/}" fi # 区分文件和目录:文件取父目录,目录直接用本身 if [[ -f "$path" ]]; then dir=$(dirname "$path") else dir="$path" fi # 逐级向上输出所有父目录,直到当前工作目录 while [[ "$dir" != "." ]]; do echo "$dir" dir=$(dirname "$dir") done done | sort -u
命令拆解:
git status -s -uall:用Git的porcelain极简模式输出所有变更,包括未跟踪的文件/目录,确保不会漏掉任何变更项awk '{print $2}':提取每行里的路径部分(因为git status -s的格式是「状态码 + 空格 + 路径」)- 循环处理每个路径:
- 先清理目录路径末尾的
/,避免dirname命令报错 - 判断是文件还是目录:如果是文件,先获取它的直接父目录;如果是目录,直接用这个目录路径
- 逐级向上遍历父目录,每一步输出目录名,直到到达当前工作目录(
.)
- 先清理目录路径末尾的
sort -u:对输出的目录列表去重并排序,得到唯一的目录集合
方法2:结合git diff和git ls-files的精准处理
如果你想更精准地拆分已变更文件和未跟踪文件的处理,可以用这个方法:
( git diff --name-only --cached --others; git ls-files --others --exclude-standard ) | while read path; do if [[ -f "$path" ]]; then dir=$(dirname "$path") else dir="$path" fi while [[ "$dir" != "." ]]; do echo "$dir" dir=$(dirname "$dir") done done | sort -u
命令拆解:
git diff --name-only --cached --others:列出已暂存、未暂存的变更文件,以及未跟踪的文件git ls-files --others --exclude-standard:列出所有未跟踪且不在.gitignore规则内的文件/目录- 后续的路径处理和方法1完全一致,最终输出去重后的所有层级父目录
简化需求:仅获取直接父目录
如果你只需要每个变更文件/目录的直接父目录(比如stack/pipeline.yaml只取stack,而不是所有层级),可以用更简洁的命令:
git status -s -uall | awk '{print $2}' | sed 's/\/$//' | xargs dirname 2>/dev/null | sort -u | grep -v '^\.$'
说明:
sed 's/\/$//':去掉目录路径末尾的/xargs dirname:批量获取每个路径的直接父目录2>/dev/null:忽略dirname处理根目录路径时的报错grep -v '^\.$':过滤掉当前工作目录(.)的输出
内容的提问来源于stack exchange,提问作者Biplob Biswas
相关产品推荐
相关产品推荐

