Ensure merged work.
authorStephen Haberman <stephen@exigencecorp.com>
Mon, 7 Jul 2008 22:38:47 +0000 (17:38 -0500)
committerStephen Haberman <stephen@exigencecorp.com>
Mon, 7 Jul 2008 22:39:42 +0000 (17:39 -0500)
remerge.sh [new file with mode: 0644]
server/update-ensure-merged [new file with mode: 0644]
tests/t2500-server-update-ensure-merged.sh [new file with mode: 0644]

diff --git a/remerge.sh b/remerge.sh
new file mode 100644 (file)
index 0000000..b328f92
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+git rev-list --first-parent "stable..HEAD" | while read commit ; do
+       number_of_parents=$(git rev-list -n 1 --parents $commit | sed 's/ /\n/g' | grep -v $commit | wc -l)
+       if [[ $number_of_parents > 1 ]] ; then
+               # For each parent
+               git rev-list --no-walk --parents $commit | sed 's/ /\n/g' | grep -v $commit | while read parent ; do
+                       echo "merge=$commit parent=$parent"
+                       # Does this parent have any children besides us?
+                       #
+                       # List the parents of all branch commits (after stable/parent), find
+                       # those that include our parent, get their sha1, remove our merge
+                       git rev-list --parents --branches ^stable "^$parent" | grep $parent | gawk '{print $1}' | grep -v $commit | while read child ; do
+                               echo "child $child"
+                               git rev-list "$child" "^$commit"
+                       done
+                       # Find any commits in the parent (and another branch) but not us--that means we need it
+                       # number_missing=$(git rev-list "$parent" --branches "^HEAD" | wc -l)
+                       # if [[ $number_missing > 0 ]] ; then
+                       #       git rev-list "$parent" --branches "^HEAD" | xargs git name-rev
+                       # fi
+               done
+       fi
+done
+
diff --git a/server/update-ensure-merged b/server/update-ensure-merged
new file mode 100644 (file)
index 0000000..a83210a
--- /dev/null
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+#
+# When tagging the candidate branch, and commit "A"
+# has gone onto a topic branch that we previously
+# merged, reject the tag.
+#
+# * -- * -- * -- A   topic A
+#  \        \
+#   * -- *           topic B
+#          \ \
+#            *       candidate
+#
+# We want to detect A when trying to tag candidate.
+#
+# This also implements candidate protection, e.g.
+# only merges are allowed on candidate branches.
+
+# Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+echo "updating $refname $oldrev $newrev"
+fail=0
+
+case "$refname" in
+       refs/tags/*)
+               # First make sure stable hasn't moved on us
+               baserev=$(git merge-base stable $newrev)
+               stablerev=$(git rev-parse stable)
+               if [ "$baserev" != "$stablerev" ] ; then
+                       echo "----------------------------------------------------"
+                       echo
+                       echo " Rejecting $refname because you need to merge:"
+                       echo
+                       git rev-list "$baserev..$stablerev" | xargs git name-rev
+                       echo
+                       echo "----------------------------------------------------"
+                       fail=1
+               else
+
+                       # Now go back to stable and iterate through looking for commits on
+                       # our merge parents that are not within us
+                       git rev-list --first-parent "stable..$newrev" | while read commit ; do
+                               number_of_parents=$(git rev-list -n 1 --parents $commit | sed 's/ /\n/g' | grep -v $commit | wc -l)
+                               if [[ $number_of_parents > 1 ]] ; then
+                                       # For each parent
+                                       git rev-list --no-walk --parents $commit | sed 's/ /\n/g' | grep -v $commit | while read parent ; do
+                                               # Does this parent have any children besides us?
+                                               #
+                                               # List the parents of all branch commits (after stable/parent), find
+                                               # those that include our parent, get their sha1, remove our merge
+                                               git rev-list --parents --branches ^stable "^$parent" | grep $parent | gawk '{print $1}' | grep -v $commit | while read child ; do
+                                                       number_missing=$(git rev-list "$child" "^$newrev" | wc -l)
+                                                       if [[ $number_missing > 0 ]] ; then
+                                                               echo "----------------------------------------------------"
+                                                               echo
+                                                               echo " Rejecting $refname because you need to merge:"
+                                                               echo
+                                                               git rev-list "$child" "^$newrev" | xargs git name-rev
+                                                               echo
+                                                               echo "----------------------------------------------------"
+                                                               fail=1
+                                                       fi
+                                               done
+
+                                               # Find any commits in the parent (and another branch) but not us--that means we need it
+                                               # number_missing=$(git rev-list "$parent" --all "^$newrev" | wc -l)
+                                               # if [[ $number_missing > 0 ]] ; then
+                                               #       echo "----------------------------------------------------"
+                                               #       echo
+                                               #       echo " Rejecting $refname because you need to merge:"
+                                               #       echo
+                                               #       git rev-list "$parent" --all "^$newrev" | xargs git name-rev
+                                               #       echo
+                                               #       echo "----------------------------------------------------"
+                                               #       exit 1
+                                               # fi
+                                       done
+                               fi
+                       done
+
+               fi
+               ;;
+
+       refs/heads/candidate*)
+               # Look at commits between stable and us--ignoring those brought in by merges
+               git rev-list --first-parent "$newrev" ^stable | while read commit ; do
+                       number_of_parents=$(git rev-list -n 1 --parents $commit | sed 's/ /\n/g' | grep -v $commit | wc -l)
+                       if [[ $number_of_parents == 1 ]] ; then
+                               echo "----------------------------------------------------"
+                               echo
+                               echo " Candidate branches must be only merges"
+                               echo
+                               echo "----------------------------------------------------"
+                               fail=1
+                       fi
+               done
+               ;;
+
+       *)
+               ;;
+esac
+
+exit "$fail"
+
diff --git a/tests/t2500-server-update-ensure-merged.sh b/tests/t2500-server-update-ensure-merged.sh
new file mode 100644 (file)
index 0000000..2878996
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/sh
+
+test_description='server update ensure merged'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       echo "setup" >a &&
+       git add a &&
+       git commit -m "setup" &&
+       git clone ./. server &&
+       rm -fr server/.git/hooks &&
+       git remote add origin ./server &&
+       git config --add branch.master.remote origin &&
+       git config --add branch.master.merge refs/heads/master &&
+       git fetch &&
+       git checkout -b stable &&
+       git push origin stable
+'
+
+install_server_hook 'update-ensure-merged' 'update'
+
+test_expect_success 'pushing just topic is okay' '
+       git checkout -b topic &&
+       echo "$test_name" >a &&
+       git commit -a -m "$test_name on topic" &&
+       git push origin topic
+'
+
+test_expect_success 'if topic moves on, tagging candidate requires a merge' '
+       git checkout -b candidate stable &&
+       git merge topic --no-ff &&
+       git push &&
+
+       git checkout topic &&
+       echo "$test_name on topic" >a &&
+       git commit -a -m "$test_name on topic" &&
+       git push &&
+
+       git checkout candidate &&
+       git tag -a -m "Tagging candidate" deployment-1 &&
+       ! git push --tags 2>push.err &&
+       cat push.err | grep "Rejecting refs/tags/deployment-1 because you need to merge" &&
+       cat push.err | grep "topic" &&
+
+       git merge topic &&
+       git tag -d deployment-1 &&
+       git tag -a -m "Tagging candidate" deployment-1 &&
+       git push --tags
+'
+
+test_expect_success 'if stable moves on, tagging candidate requires a merge' '
+       git checkout stable &&
+       echo "$test_name on stable" >a.stable &&
+       git add a.stable &&
+       git commit -a -m "$test_name on stable" &&
+       git push &&
+
+       git checkout candidate &&
+       git tag -a -m "Tagging candidate" deployment-2 &&
+       ! git push --tags 2>push.err &&
+       cat push.err | grep "Rejecting refs/tags/deployment-2 because you need to merge" &&
+       cat push.err | grep "stable" &&
+
+       git merge stable &&
+       git tag -d deployment-2 &&
+       git tag -a -m "Tagging candidate" deployment-2 &&
+       git push --tags
+'
+
+test_expect_success 'when creating a candidate, it must be a merge' '
+       git checkout -b topic2 stable &&
+       echo "$test_name on topic2" >a &&
+       git commit -a -m "$test_name on topic2" &&
+       git push origin topic2 &&
+
+       git checkout -b candidate2 stable &&
+       git merge topic2 &&
+       ! git push origin candidate2 2>push.err &&
+       cat push.err | grep "Candidate branches must be only merges" &&
+
+       git reset --hard HEAD^ &&
+       git merge --no-ff topic2 &&
+       git push origin candidate2
+'
+
+test_done
+