From: Stephen Haberman Date: Mon, 7 Jul 2008 22:38:47 +0000 (-0500) Subject: Ensure merged work. X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=7ebafdbba49a173ea658a767fb2e776b5a58c452;p=git-central.git Ensure merged work. --- diff --git a/remerge.sh b/remerge.sh new file mode 100644 index 0000000..b328f92 --- /dev/null +++ b/remerge.sh @@ -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 index 0000000..a83210a --- /dev/null +++ b/server/update-ensure-merged @@ -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 index 0000000..2878996 --- /dev/null +++ b/tests/t2500-server-update-ensure-merged.sh @@ -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 +