Better tattoo.
authorStephen Haberman <stephen@exigencecorp.com>
Thu, 28 Aug 2008 16:03:58 +0000 (11:03 -0500)
committerStephen Haberman <stephen@exigencecorp.com>
Thu, 28 Aug 2008 16:03:58 +0000 (11:03 -0500)
scripts/gc-tattoo
server/update-stable
tests/t2102-server-update-stable-candidate.sh
tests/t5500-script-tattoo.sh

index 7ad1e54..8244c04 100644 (file)
@@ -1,40 +1,79 @@
 #!/bin/sh
 
 head=$(git rev-parse HEAD)
-branch=$(git symbolic-ref --quiet HEAD)
+
+# Watch out for the very first commit in the repo because we use head^ later
+git rev-parse --verify --quiet "$head^" >/dev/null
 if [ $? -ne 0 ] ; then
-       echo "unknown"
-       exit 1
+       echo "0"
+       exit 0
 fi
 
-case "$branch" in
-       refs/heads/*)
-               branch=${branch##refs/heads/}
-               ;;
-       *)
-               echo "unknown"
-               exit 1
-               ;;
-esac
-
-# Ensure pushed
-git branch -r --contains $head | grep --quiet "origin/$branch"
-if [ $? -ne 0 ] ; then
-       echo "$branch has not been pushed"
+# A --- B --- C    stable
+# |\         /
+# | D ----- E      topic1
+#  \       /
+#   F --- G        topic2
+#
+# topic1 stable result
+#  D      A      contains, merge base=A
+#  D      C      contains, merge base=A
+#  E      A      contains, merge base=E
+#  E      C      contains, merge base=A
+
+#
+# * --- * --------- *   stable
+# |\     \
+# | A --- B ---- C      topic1
+# \             /
+#  D --- E --- F        topic2
+#
+# F: contains=topic1,topic2
+# C: contains=topic1
+
+contains=($(git branch -r --contains $head))
+if [ ${#contains[@]} -eq 0 ] ; then
+       echo "$head has not been pushed"
        exit 1
 fi
 
-# Handle stable special to look for the annotated tag
-if [ "$branch" == "stable" ] ; then
-       describe=$(git describe $head 2>/dev/null)
+potential=" "
+for branch in ${contains[@]} ; do
+       branch=${branch##origin/}
+       #echo "branch=$branch"
+
+       # Walk back until we hit a baserev that is not the branch_tip itself (because it was merged)
+       branch_tip=$(git rev-parse origin/$branch)
+       stable_rev=$(git rev-parse origin/stable)
+       stable_base=$(git merge-base "$branch_tip" "$stable_rev")
+
+       # echo "stable_base=$stable_base"
+       while [ "$stable_base" == "$branch_tip" ] ; do
+               stable_rev=$(git rev-parse "${stable_rev}^")
+               stable_base=$(git merge-base "$branch_tip" "$stable_rev")
+       done
+       # echo "stable_base=$stable_base"
+
+       git rev-list --first-parent $stable_base..$branch_tip | grep --quiet "$head"
        if [ $? -eq 0 ] ; then
-               echo "$describe"
-       else
-               echo "stable-$head"
+               if [ "$branch" == "stable" ] ; then
+                       describe=$(git describe $head 2>/dev/null)
+                       if [ $? -eq 0 ] ; then
+                               potential="$potential $describe"
+                       else
+                               potential="$potential stable-$head"
+                       fi
+               else
+                       number=$(git rev-list --first-parent "$stable_base..$head" | wc -l)
+                       potential="$potential $branch-$number"
+               fi
        fi
-       exit 0
-fi
+done
 
-number=$(git rev-list --first-parent "$head" ^origin/stable | wc -l)
-echo "$branch-$number"
+potential=($potential)
+if [ ${#potential[@]} -eq 1 ] ; then
+       echo "${potential[0]}"
+else
+       echo "unknown"
+fi
 
index 020cd90..c816750 100644 (file)
@@ -81,6 +81,18 @@ if [ "$change_type" != "update" ] ; then
        exit 0
 fi
 
+# The tip must always be new
+already=$(git branch --contains "$newrev")
+if [ "$already" != "" ] ; then
+       already=${already##  }
+       echo "----------------------------------------------------"
+       echo
+       echo "$short_refname is already referred to by $already"
+       echo
+       echo "----------------------------------------------------"
+       exit 1
+fi
+
 if [ "$short_refname" == "stable" ] ; then
        # Stable enforcement
 
index 8a5711d..c62391d 100644 (file)
@@ -82,13 +82,30 @@ test_expect_success 'topic1 cannot be changed' '
        # It is already changed but error message should chagne
        git checkout topic1 &&
        ! git push origin topic1 2>push.err &&
-       cat push.err | grep "topic1 has been merged into stable"
+       cat push.err | grep "topic1 has been merged into stable" &&
+       git reset --hard HEAD^
 '
 
 test_expect_success 'topic3 cannot initially be created on stable' '
        git checkout -b topic3 stable &&
        ! git push origin topic3 2>push.err &&
-       cat push.err | grep "Creating a branch must include new commits"
+       cat push.err | grep "Creating a branch must include new commits" &&
+
+       echo "$test_name" >a.topic3 &&
+       git add a.topic3 &&
+       git commit -m "$test_name" &&
+       git push origin topic3
+'
+
+test_expect_success 'topic4 cannot point to the same place as topic4' '
+       git checkout -b topic4 topic3 &&
+       echo "$test_name" >a.topic4 &&
+       git add a.topic4 &&
+       git commit -m "making topic4" &&
+       git push origin topic4 &&
+
+       ! git push origin topic4:topic3 2>push.err &&
+       cat push.err | grep "topic3 is already referred to by topic4"
 '
 
 test_done
index 7352183..bab6dd2 100644 (file)
@@ -17,61 +17,81 @@ test_expect_success 'setup' '
        git push origin stable
 '
 
-test_expect_success 'tattoo 0' '
+# tattoo makes assumptions based on the update stable hook sanity checks
+install_update_hook 'update-stable'
+
+test_expect_success 'tattoo of first commit' '
+       gc-tattoo | grep 0
+'
+
+test_expect_success 'tattoo 1' '
        git checkout -b topic1 &&
+       echo "$test_name" >a.topic1 &&
+       git add a.topic1 &&
+       git commit -a -m "move topic1-1" &&
        git push origin topic1 &&
-       gc-tattoo | grep topic1-0
+       gc-tattoo | grep topic1-1
 '
 
-test_expect_success 'tattoo 1' '
+test_expect_success 'tattoo 2' '
        echo "$test_name" >a &&
-       git commit -a -m "make topic1-1" &&
+       git commit -a -m "make topic1-2" &&
        git push origin topic1 &&
-       gc-tattoo | grep topic1-1
+       gc-tattoo | grep topic1-2
 '
 
-test_expect_success 'merge topic2 topic1 as tattoo 2' '
+test_expect_success 'merge topic2 into topic1 as tattoo 3' '
        git checkout -b topic2 stable &&
        echo "$test_name" >a.topic2 &&
-       git add a.topic2
-       git commit -m "make topic2" &&
+       git add a.topic2 &&
+       git commit -m "make topic2-1" &&
        git push origin topic2 &&
-       gc-tattoo | grep topic2-1
+       gc-tattoo | grep topic2-1 &&
 
        git checkout topic1 &&
        git merge topic2 &&
        git push origin topic1 &&
-       gc-tattoo | grep topic1-2
-'
+       gc-tattoo | grep topic1-3 &&
 
-test_expect_success 'stable without a tag' '
-       git checkout stable &&
-       head=$(git rev-parse HEAD) &&
-       gc-tattoo | grep "stable-$head"
-'
-
-test_expect_success 'stable with a tag' '
-       git tag -m "1.0" 1.0 &&
-       gc-tattoo | grep "1.0"
+       git checkout topic2 &&
+       gc-tattoo | grep topic2-1
 '
 
 test_expect_success 'fails if not pushed' '
        git checkout topic1 &&
        echo "$test_name" >a &&
-       git commit -a -m "make topic1-3" &&
-       gc-tattoo | grep "topic1 has not been pushed"
+       git commit -a -m "make topic1-4" &&
+       head=$(git rev-parse HEAD) &&
+       gc-tattoo | grep "$head has not been pushed" &&
+       git push origin topic1 &&
+       gc-tattoo | grep topic1-4
 '
 
 test_expect_success 'stable fails if not pushed' '
        git checkout stable &&
        git merge --no-ff topic1 &&
-       gc-tattoo | grep "stable has not been pushed"
+       head=$(git rev-parse HEAD) &&
+       gc-tattoo | grep "$head has not been pushed" &&
+       git push &&
+       gc-tattoo | grep "stable-$head"
+'
+
+test_expect_success 'stable without a tag' '
+       git checkout stable &&
+       head=$(git rev-parse HEAD) &&
+       gc-tattoo | grep "stable-$head"
+'
+
+test_expect_success 'stable with a tag' '
+       git tag -m "1.0" 1.0 &&
+       gc-tattoo | grep "1.0"
 '
 
 test_expect_success 'use origin stable not local' '
-       git checkout topic1 &&
-       git push origin topic1 &&
-       gc-tattoo | grep "topic1-3"
+       git checkout origin/stable &&
+       git branch -d stable &&
+       git checkout topic2 &&
+       gc-tattoo | grep "topic2-1"
 '
 
 test_done