summaryrefslogtreecommitdiffstats
path: root/bin/git-note-review
blob: 6daeebafb121c5629e91ea089f7a280a37de4403 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#! /bin/sh
# Copyright (C) 2015 The Qt Company Ltd.
# Contact: http://www.qt.io/licensing/
#
# You may use this file under the terms of the 3-clause BSD license.
# See the file LICENSE from this package for details.
#

force=false
remove=false
while test $# != 0; do
    case $1 in
        -f) force=true;;
        -r) remove=true;;
        -*) echo "Unrecognized option $1." >&2; exit 1;;
        *) break;;
    esac
    shift
done

if test -z "$2"; then
    cat >&2 <<EOF
Usage: $0 [-f] [-r] <user> <sha-1>...

git-note-review adds Reviewed-by: lines to the log messages of the
named commits. Commits can be specified as either as a single sha1 or
as a sha1_excl..sha1_incl range (see git rev-list).
If any <whatever>-by: tag with the specified <user> is found to be
already present in a given commit, the commit is skipped.
If -f is specified, the check whether the commits were already pushed
is omitted. This only makes sense if you are planning to make a forced
push.
If -r is specified, the named user's reviews are removed from the commits.
EOF
    exit 1
fi

GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ -z "$GIT_DIR" ]; then
    echo >&2 "Not a git repository."
    exit 1
fi
cd "$GIT_DIR/.."

REF=$(git symbolic-ref HEAD 2>/dev/null)
if [ -z "$REF" ]; then
    echo >&2 "Not on a branch."
    exit 1
fi

if test -n "`git diff HEAD`" ; then
    echo "You have uncommited changes. Please commit or stash them first." >&2
    exit 1
fi

who=$1
shift
SHA1s=
firstSHA1=
fail=false
for j in "$@"; do
    if test -z "${j##*..*}"; then
        if ! jj=`git rev-list $j 2> /dev/null`; then
            echo "Cannot parse commit range $j." >&2
            fail=true
            continue
        fi
        j=$jj
    fi
    for ii in $j; do
        if ! i=`git rev-parse --short $ii 2> /dev/null`; then
            echo "Cannot parse commit id $ii." >&2
            fail=true
            continue
        fi
        if test -n "`git rev-list -1 $i ^HEAD`"; then
            echo "Commit $i is not on current branch. Did you rebase it meanwhile?" >&2
            fail=true
            continue
        fi
        git log -1 --pretty=%b $i | egrep -q -i "^[-[:alpha:]]+-by: *$who\$" && hit=true || hit=false
        if $hit && ! $remove; then
            echo "Commit $i already noted as reviewed by $who."
        elif ! $hit && $remove; then
            echo "Commit $i not noted as reviewed by $who."
        else
            if test -z "$firstSHA1"; then
                firstSHA1=`git rev-parse $i`
                SHA1s=$i
            else
                firstSHA1=`git merge-base $firstSHA1 $i`
                SHA1s="$SHA1s|$i"
            fi
        fi
    done
done
if $fail; then
    echo "Exiting due to fatal errors." >&2
    exit 1
fi
if test -z "$SHA1s"; then
    echo "No commits to change." >&2
    exit 0
fi

# This would be pretty much bullet-proof, but also a lot slower.
#if test -z "$(git rev-list -1 $firstSHA1 --not $(git for-each-ref --format='%(objectname)' refs/remotes/))"; then
#    echo "$firstSHA1 has already been pushed - cannot edit it." >&2
#    exit 1
#fi
# This should be Good Enough (TM), and it is rather fast.
if ! $force && test -n "$(git rev-list -1 $firstSHA1^..@{upstream})"; then
    echo "Commit `git rev-parse --short $firstSHA1` has already been pushed - cannot edit it." >&2
    exit 1
fi

if ! $remove; then
    script='s/^\\(Reviewed-by:\\) *\\(pending\\|tbd\\|TBD\\)\$/\\1 '"$who"'/;t nx
\${
/^[-[:alpha:]]\+:/!a\\

a\\
Reviewed-by: '"$who"'
}
b
:nx;n;b nx'
else
    script='/^[-[:alpha:]]\\+-by: *'"$who"'\$/d'
fi

git filter-branch --force --original refs/note-review-backup --msg-filter '
    if echo $GIT_COMMIT | egrep -q "^('"$SHA1s"')"; then
        sed "'"$script"'"
    else
        cat
    fi
' $firstSHA1^..$REF || exit 1
rm -rf $GIT_DIR/refs/note-review-backup # we have the reflog, so what