6c89e51374b8ed56b2dffaa2d71b0d26d9eef697
[git-central.git] / server / update-stable
1 #!/bin/sh
2
3 #
4 # This enforces stable only moving in the approved way, which
5 # is via empty (no change) merge commits. The rationale is that
6 # in the DAG we want a simple, one-commit move from each release
7 # to the next.
8 #
9 # We started out with:
10 #
11 # * -- A                stable
12 #  \    \
13 #   \    * -- * -- B    topic1
14 #    \           /
15 #     * -- * -- *       topic2
16 #
17 # And then publishing stable was a matter of fast-forwarding
18 # from A to B.
19 #
20 # In a complicated (non-rebased) DAG, this becomes hard to follow,
21 # so want we want instead is:
22 #
23 # * -- A ----------- C  stable
24 #  \    \           /
25 #   \    * -- * -- B    topic1
26 #    \           /
27 #     * -- * -- *       topic2
28 #
29 # Where commit C lists as it's first parent the prior stable
30 # commit and as it's second parent the release candidate. No
31 # other parents are allowed (e.g. no octopus merges here, which
32 # would insinuate qa didn't happen on the merged result).
33 #
34 # Also, we want to enforce that C does not actually introduce
35 # any diffs to the files between B and C--otherwise this changes
36 # would not have appeared in QA.
37 #
38
39 refname="$1"
40 oldrev="$2"
41 newrev="$3"
42
43 if expr "$oldrev" : '0*$' >/dev/null ; then
44         exit 0
45 fi
46
47 if [ "$refname" != "refs/heads/stable" ] ; then
48         exit 0
49 fi
50
51 # read backwards:
52 # - all commits from old..new
53 # - unless they were already pointed to by a branch
54 # = all new commits on stable
55 count=$(git rev-parse --not --branches | git rev-list --stdin $oldrev..$newrev | wc -l)
56 if [ "$count" -ne "1" ] ; then
57         echo "----------------------------------------------------"
58         echo
59         echo "Moving stable must entail a single commit"
60         echo
61         echo "----------------------------------------------------"
62         exit 1
63 fi
64
65 number_of_parents=$(git rev-list --no-walk --parents $newrev | sed 's/ /\n/g' | grep -v $newrev | wc -l)
66 if [ "$number_of_parents" -ne "2" ] ; then
67         echo "----------------------------------------------------"
68         echo
69         echo "Moving stable must entail a merge commit"
70         echo
71         echo "----------------------------------------------------"
72         exit 1
73 fi
74
75 first_parent=$(git rev-list --no-walk --parents $newrev | sed 's/ /\n/g' | grep -v $newrev | head --lines=1)
76 if [ "$first_parent" != "$oldrev" ] ; then
77         echo "----------------------------------------------------"
78         echo
79         echo "Moving stable must have the previous stable as the first parent"
80         echo
81         echo "----------------------------------------------------"
82         exit 1
83 fi
84
85 second_parent=$(git rev-list --no-walk --parents $newrev | sed 's/ /\n/g' | grep -v $newrev | tail --lines=1)
86 changed_lines=$(git diff $second_parent..$newrev | wc -l)
87 if [ "$changed_lines" -ne "0" ] ; then
88         echo "----------------------------------------------------"
89         echo
90         echo "Moving stable must not result in any changes from $second_parent"
91         echo
92         echo "----------------------------------------------------"
93         exit 1
94 fi
95