我想获得对文件做出贡献的所有作者(工作)。另外,我想要文件(工作)每个作者的行数。最后我还想要每个作者贡献的每个行号。格式不应为 1, 2, 3, 4, 5, 11, 12, 13, 14,而应为 1-5、11-14 之类的格式。这可以在命令行上以“简单”的方式实现吗?我无法手动执行任何操作,因为我们有数千个文件,其中包含大约 200 万行代码。
files=$(git ls-tree -r HEAD | cut -c54-)
for file in $files
do
echo $file
git blame $file --line-porcelain | grep "^author " | sort | uniq -c | sort -r
done
除了行号之外正在做我想做的事情。
就获取每个作者编写的行号列表而言,它在(不那么)简单的命令管道中是可行的
git blame $file --line-porcelain |
grep "^author " |
cat -n |
awk '{
author = substr($0, index($0, $3));
if(authorLines[author] != "")
authorLines[author] = authorLines[author] ", " $1;
else
authorLines[author] = $1;
}
END {
for (author in authorLines)
print author ": " authorLines[author];
}'
这个 awk 命令的工作原理是作者通过将 awk 当前所在行 ($0) 的第三个字段 ($3) 作为子字符串的起始索引来找到的。然后,它会针对该作者保存行号 ($1),并在第一次发生时进行一些逻辑处理。最后输出列表。
从列表中创建范围需要更多的脚本。
# Function to convert a list of numbers into ranges
convert_to_ranges() {
local numbers=($(echo "$1" | tr ',' '\n' | sort -n | uniq)) # Split, sort, and unique filter
local range_start=""
local range_end=""
local result=""
for number in "${numbers[@]}"; do
if [[ -z "$range_start" ]]; then
range_start=$number
range_end=$number
elif [[ $((number - range_end)) -eq 1 ]]; then
range_end=$number
else
result+=$(format_range $range_start $range_end)","
range_start=$number
range_end=$number
fi
done
result+=$(format_range $range_start $range_end)
echo $result
}
# Function to format a range or a single number
format_range() {
if [[ $1 -eq $2 ]]; then
echo -n "$1"
else
echo -n "$1-$2"
fi
}
这些函数用于对数字列表进行计数,检查它们是否连续,然后将它们格式化为范围。
然后可以针对 bash 脚本中的第一个命令运行:
# Capture the output of git blame and awk processing
author_lines=$(git blame $file --line-porcelain |
grep "^author " |
cat -n |
awk '{
author = substr($0, index($0, $3));
if(authorLines[author] != "")
authorLines[author] = authorLines[author] ", " $1;
else
authorLines[author] = $1;
}
END {
for (author in authorLines)
print author ": " authorLines[author];
}')
# Process each author's lines and convert to ranges
echo "$author_lines" | while read -r line; do
author=$(echo "$line" | cut -d ':' -f 1)
lines=$(echo "$line" | cut -d ':' -f 2-)
ranges=$(convert_to_ranges "$lines")
echo "$author: $ranges"
done
这应该会给你一个看起来像这样的输出,具体取决于你的文件:
John : 1-3,48,55-70,100-105,110-112,114-116,118,125,127-128,130-131,136,138-170,172,174-180,192,195-202
Sandra : 4-47,49-50,54,71-99,106-109,113,117,119-124,126,129,132-135,137,171,173,181-191,193-194,203-471
Frank : 51-53