在 git 中按作者获取每个文件的所有行

问题描述 投票:0回答:1

我想获得对文件做出贡献的所有作者(工作)。另外,我想要文件(工作)每个作者的行数。最后我还想要每个作者贡献的每个行号。格式不应为 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

除了行号之外正在做我想做的事情。

bash git shell gitlab git-blame
1个回答
0
投票

就获取每个作者编写的行号列表而言,它在(不那么)简单的命令管道中是可行的

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
© www.soinside.com 2019 - 2024. All rights reserved.