On 2014-08-17 06:29-0700 phil rosenberg wrote:

Hi Alan
I'm not great with shell scripts - I use them so infrequently I never remember 
the syntax. However I have quickly tried to modify the hook 
fromhttps://gist.github.com/caniszczyk/1327469. Basically you are trying to do 
something like:

git rev-list --first-parent newrev | grep `git rev-list --first-parent 
--max-count=1 oldrev`

where newrev is the revision being pushed and oldrev is the revision being 
updated.

If this gives an empty string then then newrev is not a direct descendant of 
oldrev. This could be because the merge was done the wrong way round (which is 
the check described on the CMAKE page) or because someone has modified oldrev 
on the server before the push occurred.

The command works because git rev-list --first-parent commit lists the sha 
values for each parent of the commit choosing only the first parent, rather 
than the merged in parent in the case of a merge. Therefore if you have merged 
the wrong way the new commit will not inherit from the parent of the old 
commit. Note that the one exception is a fast forward commit, however in this 
case the result is identical no matter which way the merge was performed so it 
makes no difference.

If you intend to have a "next" branch then you could also ensure that the topic 
branch being merged in inherits from master (instead of next or bugfixes or whatever), by 
branching next, making a change to master. Finding the sha for this first commit which is 
not on next and grepping for it in the same way as above.

Attached is my quick hack of that script which just replaces the requirement 
for fast forward merges only, with the requirement above - I haven't tested it 
or tried to run it and it will have windows line endings but I haven't got time 
right now. The syntax might be wrong, but I'm sure you can see the intent. I'm 
sure you can have a look at it and have a play with the git rev-list command to 
see what is happening and add stuff if you like.


Hi Phil:

I am impressed at how far you have gotten with this! This sounds like
it may lead to the exact server-side hook that we need. Note, it is
going to take me a while to follow what you have discovered in any
detail because I am distracted by the client-side hook implementation
that should nicely complement the server-side hook implementation, and
I still need to get up to speed on some of the commands you are using
and relate them to what the wiki says about maintaining a "clean shape
of history".

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
#!/bin/sh

#
# For each ref, validate the commit.
#
# - It disallows deleting branches without a /.
# - It disallows non fast-forward on branches without a /.
# - It disallows deleting tags without a /.
# - It disallows unannotated tags to be pushed.

validate_ref()
{
        # --- Arguments
        oldrev=$(git rev-parse $1)
        newrev=$(git rev-parse $2)
        refname="$3"

        allownonffpush=$( git config --bool hooks.allownonffpush )
        allowdeletebranch=$( git config --bool hooks.allowdeletebranch )
        allowdeletetag=$( git config --bool hooks.allowdeletetag )
        allowcreatenottopicbranch=$( git config --bool 
hooks.allowcreatenottopicbranch )
        # oldrev could be 0s which means creating refname
        # newrev could be 0s which means deleting refname

        case "$refname" in
                refs/heads/*)
                        branch=$(expr "$refname" : "refs/heads/\(.*\)")
                        topicbranch=$(expr "$branch" : "\(.*/.*\)")
                        topicuser=$(expr "$branch" : "\(.*\)/.*")
                        if [ 0 -ne $(expr "$newrev" : "0*$") ]; then # deleting
                                # only topic branches can be deleted
                                if [ "$allowdeletebranch" != "true" -a -z 
"$topicbranch" ]; then
                                        fail=1
                                        echo >&2 "*** Deleting the branch 
$branch is not permitted. ***"
                                        return
                                fi
                                if [  "$allowdeletebranch" != "true" -a "$USER" 
!= "$topicuser" ]; then
                                        fail=1
                                        echo >&2 "*** Deleting the branch 
$branch is not permitted by $USER. ***"
                                        return
                                fi
                                return # Don't need to validate old revision
                        else #updating
                                if [ 0 -ne $(expr "$oldrev" : "0*$") ]; then # 
pushing a new branch
                                        if [ "$allowcreatenottopicbranch" != 
"true" -a -z "$topicbranch" ]; then
                                                fail=1
                                                echo >&2 "*** creation of 
branch $branch is not permitted. ***"
                                        fi
                                        return # it's not a FF merge
                                fi
                                oldrevparent=`git rev-list --first-parent 
--max-count=1 oldrev`
                                if [ "" -eq `git rev-list --first-parent newrev 
| grep oldrevparent` ]; then # non fast-forward
                                        fail=1
                                        echo >&2 "*** Branch merge has been 
performed the wrong way round or the branch has been modified since the merge. 
***"
                                fi
                        fi
                        ;;
                refs/tags/*)
                    tag=$(expr "$refname" : "refs/tags/\(.*\)")
                        topictag=$(expr "$tag" : "\(.*/.*\)")
                        topicuser=$(expr "$tag" : "\(.*\)/.*")
                        if [ 0 -ne $(expr "$newrev" : "0*$") ]; then # deleting
                                # only topic tags can be deleted
                                if [ "$allowdeletetag" != "true" -a -z 
"$topictag" ]; then
                                        fail=1
                                        echo >&2 "*** Deleting the tag $tag is 
not permitted. ***"
                                        return
                                fi
                                if [  "$allowdeletetag" != "true" -a "$USER" != 
"$topicuser" ]; then
                                        fail=1
                                        echo >&2 "*** Deleting the tag $tag is 
not permitted by $USER. ***"
                                        return
                                fi
                                return
                        fi
                        ;;
                *)
                        fail=1
                        echo >&2 "*** pre-receive hook does not understand ref 
$refname in this repository. ***"
                        echo >&2 "*** Contact the repository administrator. ***"
                        ;;
        esac
}

fail=""

# Allow dual mode: run from the command line just like the update hook, or
# if no arguments are given then run as a hook script
if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
        # Output to the terminal in command line mode - if someone wanted to
        # resend an email; they could redirect the output to sendmail
        # themselves
        PAGER= validate_ref $2 $3 $1
else
        while read oldrev newrev refname
        do
                validate_ref $oldrev $newrev $refname
        done
fi

if [ -n "$fail" ]; then
        exit $fail
fi
------------------------------------------------------------------------------
_______________________________________________
Plplot-devel mailing list
Plplot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/plplot-devel

Reply via email to