-1

I need a way to delete Git repository branches more conveniently cause an `update hook' is blocking them:

Command

git push -v -f --no-verify --delete origin test_branch

Output

remote: fatal: Not a valid commit name 0000000000000000000000000000000000000000
remote: error: hook declined to update refs/heads/test_branch

I'm currently disabling the update hook temporarily, performing the delete, and then restoring the hook, so I'm looking for suggestions for something better, even perhaps altering the Perl Git hook.

I don't know anything about Perl or Git hooks, so I have these questions

  1. I can't give a message to the push action. What is the best way to achieve something like this?

  2. Is there any way to get the push --delete event from the hook?

    Something like

    if ${push --delete} then skip hook checks
    
  3. Is there any way to create a custom parameter to the push operation in order to skip the hook? Something like

    if command line contains --imgod then skip hook checks
    

I'm totally groping in the dark.

This is the update hook definition from the Git documentation

UPDATE HOOK This hook is invoked by git-receive-pack on the remote repository, which happens when a git push is done on a local repository. Just before updating the ref on the remote repository, the update hook is invoked. Its exit status determines the success or failure of the ref update.

The hook executes once for each ref to be updated, and takes three parameters:

  • the name of the ref being updated,

  • the old object name stored in the ref,

  • and the new object name to be stored in the ref

A zero exit from the update hook allows the ref to be updated. Exiting with a non-zero status prevents git-receive-pack from updating that ref.

This hook can be used to prevent forced update on certain refs by making sure that the object name is a commit object that is a descendant of the commit object named by the old object name. That is, to enforce a "fast-forward only" policy.

It could also be used to log the old..new status. However, it does not know the entire set of branches, so it would end up firing one e-mail per ref when used naively, though. The post-receive hook is more suited to that.

In an environment that restricts the users' access only to git commands over the wire, this hook can be used to implement access control without relying on filesystem ownership and group membership. See git-shell[1] for how you might use the login shell to restrict the user’s access to only git commands.

Both standard output and standard error output are forwarded to git send-pack on the other end, so you can simply echo messages for the user.

The default update hook, when enabled—​and with hooks.allowunannotated config option unset or set to false—​prevents unannotated tags to be pushed.

ANSWER:

i found a way to catch the branch deletion event into the update hook and to skip the logic of the hook in all the other cases:

zero="0000000000000000000000000000000000000000"
if [ "$refname" == "refs/heads/*"] && [ "$newrev" == "$zero" ]; 
then
      exit 0
else
      perform_your_checks()
fi

more info can be found in the update.sample GIT template.

ivoruJavaBoy
  • 1,307
  • 2
  • 19
  • 39
  • Can you show the hook? See e.g. [here](https://stackoverflow.com/questions/6644329/block-a-git-branch-from-being-pushed) for some ideas. – Christoph Dec 05 '17 at 16:17
  • I'm sorry, the hook is too big to be shown, but the thing is that it needs to be the way it is. I can improve it, introducing a condition about when the action is about "delete a branch", the problem is that i need to understand how to identify that action. – ivoruJavaBoy Dec 05 '17 at 16:23
  • 1
    So your question is more like how to a adjust a hook "to my needs"? I fear people can only help if you provide the hook and the conditions under which you want the beavior changed and how it should exactly change. – Christoph Dec 05 '17 at 16:30
  • My question is how can i get that event, the case i'm pushing a branch deletion :) – ivoruJavaBoy Dec 05 '17 at 16:46
  • *"... the hook is too big to be shown, but ... it needs to be the way it is"* If that is true then I don't see how you have any options at all. The hook prohibits your deletions but that's the way it is and it needs to be that way. Please clarify. – Borodin Dec 05 '17 at 17:56
  • If you absolutely need to show very large chunks of code then it's acceptable to upload that code to something like [`pastebin`](https://pastebin.com) and add a link here. But you should do your best to make Stack Overflow posts self-contained and independent of transitory resources. – Borodin Dec 05 '17 at 18:00
  • Please provide a minimal, runnable demonstration of the problem. (See [mcve].) – ikegami Dec 05 '17 at 19:10
  • 1
    @ivoruJavaBoy: The prefered way to provide an answer to the question is to post in the answer field, even if you're answering your own question. That's encouraged by SO. That way if a better answer latter comes by, it can be voted above your original answer, and people can leave comments which pertain to your answer only, rather than have to post them on the question. – frandroid Jul 05 '19 at 01:42

2 Answers2

0
  1. I can't give a message to the push action. What is the best way to achieve something like this?

You can't. What does that even mean?

  1. Is there any way to get the push --delete event from the hook? Something like if ${push --delete} then skip hook checks

Yes, as you can see from the error message you got, in the case of a delete, the third argument ("new object name") will be 0000000000000000000000000000000000000000, which you can check for.

Is there any way to create a custom parameter to the push operation in order to skip the hook?

No. A client can't decide whether or not hooks are run on the server. This is a deliberate decision to allow servers to enforce policy through hooks.

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • about the message during push --> https://stackoverflow.com/questions/10521628/git-push-to-a-remote-repository-with-a-message :) but it does not cover my case cause I've nothing to commit – ivoruJavaBoy Dec 06 '17 at 09:23
0

For someone who is still looking for solution, here is script attached. Place this script in the hooks directory of your git based SCM. Under hooks directory, you need to create a new directory named - pre-receive.d. Inside pre-receive.d/, place the script file, there is no restriction on this script file name.

#!/bin/bash

# Place this script in gitlab server directory -> <path_to_your_gitSCM_server_root>/hooks/pre-receive.d
# Create directory,if it does not exists -> mkdir -p <path_to_your_gitSCM_server_root>/hooks/pre-receive.d

# Get input data passed along pre-receive hook
read old_sha new_sha refname

zero="0000000000000000000000000000000000000000"
if [[ "$new_sha" == "$zero" ]]; 
then
    exit 0
else
    # Default separator is ' ', change to ','
    IFS=","

    # Use env variable GL_USERNAME to get the matching details from users csv file
    # This file can be easily generated from the database that you have configured for your gitSCM instance.
    # It contains records in following format - <username>,<user_email>,<user_name>
    IFS=', ' read -r -a validuserarray <<< `grep -i "$GL_USERNAME," /tmp/gituser.csv `
    valid_user_email=${validuserarray[1]}
    valid_user_name=${validuserarray[2]}

    # Get the last log user details from git log
    IFS=', ' read -r -a incoming_committer_array <<< `git log -1 "$new_sha" --pretty=%ce,%cn | tr '[:upper:]' '[:lower:]'`
    IFS=', ' read -r -a incoming_author_array <<< `git log -1 "$new_sha" --pretty=%ae,%an | tr '[:upper:]' '[:lower:]'`

    # If no match found, fail the push
    if [[ ${#validuserarray[@]} < 3 ]]; then
        echo "GL-HOOK-ERR: You are not authorised to perform this action."
        exit 1
    fi

    # Ensure no conflict markers are there
    if git diff "$old_sha" "$new_sha" | grep -qE '^\+(<<<<<<<|>>>>>>>)'; then
        echo "GL-HOOK-ERR: Code has conflict markers. Please resolve and retry."
        exit 1
    fi

    # Validate author email ends with domain.com
    if ! [[ "${incoming_author_array[0]}" =~ ^[A-Za-z0-9.]+[@]domain\.com$ ]]; then
            echo "GL-HOOK-ERR: Author email address ${incoming_author_array[0]} is invalid."
            exit 1
    fi

    # Validate committer email
    if [ "${valid_user_email}" != "${incoming_committer_array[0]}" ]; then
        echo "GL-HOOK-ERR: Committer email address ${incoming_committer_array[0]} is invalid."
        exit 1
    fi

    # Validate committer name
    if [ "${valid_user_name}" != "${incoming_committer_array[1]}" ]; then
        echo "GL-HOOK-ERR: Committer name ${incoming_committer_array[1]} is invalid."
        exit 1
    fi
    exit 0
fi

Whenever a push event is done, it will provide us with 3 values - branch, old_sha, new_sha. For all other operations, we just need to print these details and act accordingly.

rkdove96
  • 106
  • 6