Search code examples
gitgit-log

git: get *new* contributors (authors) list in release/tag


I'm preparing changelog for a release and doing some statistic.

It's quite easy to list contributors from previous release:

git shortlog -s -e -n TAG..

reviewers:

git log TAG.. | grep -Ei '(reviewed|acked)-by:' |sed 's/.*by: //' | sort | uniq -c | sort -n -r

committers:

git shortlog -s -e -n -c TAG..

But how to list new contributors (authors) since TAG (e.g. those who haven't been committing before TAG)?


Solution

  • Assuming you can use bash, there are at least two ways:

    #!/bin/bash
    
    set -e
    
    OLD_COMMIT="$1"
    NEW_COMMIT="$2"
    if test -z "$OLD_COMMIT" || test -z "$NEW_COMMIT"; then
        echo 'fatal: must provide OLD_COMMIT and NEW_COMMIT commits' >&2
        exit 1
    fi
    shift 2
    

    The first, using declarative arrays introduced back in bash 4 (emulates right outer join in imperative fashion):

    declare -A OLD_AUTHORS
    while read -r OLD_AUTHOR; do
        OLD_AUTHORS["$OLD_AUTHOR"]=1
    done < <(git log --pretty=format:%aN "$OLD_COMMIT")
    
    declare -A NEW_AUTHORS
    while read -r NEW_AUTHOR; do
        if test -z ${OLD_AUTHORS["$NEW_AUTHOR"]}; then
            NEW_AUTHORS["$NEW_AUTHOR"]=1
        fi
    done < <(git log --pretty=format:%aN "$OLD_COMMIT"~1.."$NEW_COMMIT")
    
    for NEW_AUTHOR in "${!NEW_AUTHORS[@]}"; do
        echo "$NEW_AUTHOR"
    done | sort
    

    Or, the second, using pipes and somewhat more declarative way:

    diff \
        <(git log --pretty=format:%aN "$OLD_COMMIT" | sort | uniq) \
        <(git log --pretty=format:%aN "$OLD_COMMIT"~1.."$NEW_COMMIT" | sort | uniq) \
        | grep '^> ' \
        | cut -c 3-
    

    Both of the above solutions can process the following history (git log --pretty=format:'%h %d% aN'):

    c3d766e  (tag: v2) Keith
    cffddc6  New John
    ee3cc52  Dan
    c307f13  (tag: v1) New John
    ae3c4a3  New John
    9ed948e  Old John
    7eb548a  Old John
    

    like this (show-new-authors.sh v1 v2):

    Dan
    Keith