Meta/GRADUATED: rewrite for simplicity and robustness

Junio C Hamano committed Jan 6, 2013 at 22:30 UTC 5734c66905d69410414b48d08e533268d2601cfc
1 file changed +75 -121
GRADUATED
+75 -121
@@ -1,141 +1,95 @@
1 #!/bin/sh
2
3 -# Older first!
4 -old_maint=$(
5 - git for-each-ref --format='%(refname)' 'refs/heads/maint-*' |
6 - sed -e 's|^refs/heads/||'
7 -)
8 -
9 -# Are older maint branches all included in newer ones?
10 -and_or_thru=thru prev=
11 -for m in $old_maint maint
3 +base=
4 +while :
5 do
13 - if test -n "$prev"
14 - then
15 - test "$(git rev-list $m..$prev | wc -l)" = 0 || {
16 - and_or_thru=and
17 - break
18 - }
19 - fi
20 - prev=$m
6 + case "$1" in
7 + --base=*)
8 + base=${1#*=} ;;
9 + -*)
10 + echo >&2 "Eh? $1"
11 + exit 1 ;;
12 + *)
13 + break ;;
14 + esac
15 + shift
16 done
17
23 -_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
24 -_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
18 +if test -z "$base"
19 +then
20 + describe=$(git describe "master")
21 + base=$(expr "$describe" : '\(.*\)-\([0-9]*\)-g[0-9a-f]*$') ||
22 + base="$describe"
23 +
24 + git rev-parse --verify "$base^0" >/dev/null 2>/dev/null || {
25 + echo >&2 "Eh? where is your base?"
26 + exit 1
27 + }
28 +fi
29 +
30 +topics=
31 +leftover=
32 +dothis=
33 LF='
34 '
35
28 -# disable pager
29 -GIT_PAGER=cat
30 -export GIT_PAGER
36 +defer () {
37 + leftover="$leftover$1$LF"
38 +}
39
32 -find_last_tip () {
33 - topic="$(git rev-parse --verify "$1")" integrate="$2"
34 - git rev-list --first-parent --parents "$2" |
35 - sed -n -e "
36 - /^$_x40 $_x40 $topic$/{
37 - s/^\($_x40\) $_x40 $topic$/\1/p
38 - q
39 - }
40 - "
40 +dothis () {
41 + dothis="$1$LF$LF$dothis"
42 }
43
44 +one_topic () {
45 + topic="$1" tip="$2" date="$3"
46 + case " $topics" in *" $topic "*) return ;; esac
47 + topics="$topic$topic "
48
44 -tmp=/tmp/GR.$$
49 + mergeable=no ready=no label=
50
46 -trap 'rm -f "$tmp".*' 0
51 + master_count=$(git rev-list "$base..$tip" | wc -l)
52 + maint_count=$(git rev-list "maint..$tip" | wc -l)
53
48 -git branch --merged master | sed -n -e '/\//s/^. //p' | sort >"$tmp.master"
54 + test $master_count = $maint_count && mergeable=yes
55
50 ->"$tmp.known"
51 -for m in $old_maint maint
52 -do
53 - git branch --merged $m | sed -n -e '/\//s/^. //p' | sort >"$tmp.$m"
54 - comm -12 "$tmp.$m" "$tmp.master" >"$tmp.both0"
55 - comm -23 "$tmp.both0" "$tmp.known" >"$tmp.both"
56 - if test -s "$tmp.both"
56 + if current=$(git rev-parse --verify -q "$topic^0") &&
57 + test "$current" = "$tip"
58 then
58 - echo "# Graduated to both $m $and_or_thru master"
59 - while read branch
60 - do
61 - d=$(git describe --always $branch)
62 - echo "$(git show -s --format='%ct' "$branch") $branch ;# $d"
63 - done <"$tmp.both" |
64 - sort -r -n |
65 - sed -e 's/^[0-9]* //' \
66 - -e 's/^/git branch -d /' |
67 - sort -V -k 6,6
68 - echo
69 - cat "$tmp.known" "$tmp.both" | sort >"$tmp.next"
70 - mv "$tmp.next" "$tmp.known"
71 - fi
72 -done
73 -
74 -comm -13 "$tmp.maint" "$tmp.master" |
75 -{
76 - while read topic
77 - do
78 - t=$(find_last_tip $topic master) &&
79 - test -n "$t" &&
80 - m=$(git rev-parse --verify "$t^1") &&
81 - test -n "$m" || continue
82 -
83 - # NEEDSWORK: this misses repeated merges
84 - #
85 - # o---o---maint
86 - # /
87 - # .---o---o topic
88 - # / \ \
89 - # ---o---o---*---*---master
90 -
91 - tsize=$(git rev-list "$m..$topic" | wc -l)
92 - rsize=$(git rev-list "maint..$topic" | wc -l)
93 -
94 - if test $tsize -eq $rsize
95 - then
96 - s=$(git show -s --pretty="tformat:%ct %H" $t)
97 - echo "$s $topic"
98 - else
99 - s=$(git show -s --pretty="tformat:%ct %H" $t)
100 - echo >&3 "$s $topic"
101 - fi
102 - done 3>"$tmp.unmergeable" >"$tmp.mergeable"
103 -
104 - if test -s "$tmp.unmergeable"
59 + ready=yes
60 + label="$topic"
61 + elif test -z "$current"
62 then
106 - echo ": # Graduated to master; unmergeable to maint"
107 - sort -n "$tmp.unmergeable" |
108 - while read timestamp merge topic
109 - do
110 - git show -s --pretty="format:: # %h %cd" $merge
111 - echo "git branch -d $topic"
112 - done
113 - echo
63 + ready=yes
64 + label="$tip"
65 fi
115 - if test -s "$tmp.mergeable"
116 - then
117 - sort -n "$tmp.mergeable" |
118 - while read timestamp merge topic
119 - do
120 - {
121 - git show -s --pretty="format:%h %cd" $merge
122 - git log --pretty=oneline --abbrev-commit maint..$topic
123 - } |
124 - sed -e 's/^/: # /'
125 - maint=maint
126 - these=$(git rev-list maint..$topic)
127 - for m in $old_maint maint
128 - do
129 - those=$(git rev-list $m..$topic)
130 - if test "z$these" = "z$those"
131 - then
132 - maint=$m
133 - break
134 - fi
135 - done
66
137 - echo "git checkout $maint && git merge $topic"
138 - echo
139 - done
140 - fi
67 + case "$mergeable,$ready" in
68 + no,*)
69 + defer "# $topic: not mergeable ($master_count vs $maint_count)"
70 + ;;
71 + yes,no)
72 + topic_count=$(git rev-list "$base..$current" | wc -l)
73 + defer "# $topic: not ready ($master_count vs $topic_count)"
74 + ;;
75 + yes,yes)
76 + insn="$label # $master_count ($date)"
77 + insn="$insn$LF$(git log --oneline "maint..$tip" | sed -e "s/^/# /")"
78 + dothis "$insn"
79 + ;;
80 + esac
81 +}
82 +
83 +git log --first-parent --min-parents=2 --max-parents=2 \
84 + --format='%ci %H %P %s' "$base..master" | {
85 + while read date time zone commit parent tip subject
86 + do
87 + topic=$(expr "$subject" : "Merge branch '\(.*\)'$") || {
88 + echo >&2 "Cannot parse $commit ($subject)"
89 + continue
90 + }
91 + one_topic "$topic" "$tip" "$date"
92 + done
93 + echo "$leftover"
94 + echo "$dothis"
95 }