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
}