0

I am trying to create a checkpoint using Pre-push hook in GIT where i am checking if the local branch and the remote branch name is same or not.

And allow the push only if local and remote branches are same. I was trying something like this in pre push sample hook file but its not working. Please suggest.

while read local_ref local_sha remote_ref remote_sha
do
if [ "$local_ref" != "$remote_ref" ]
then
        echo " Please check Remote and local branch names";
        exit 1

else
        exit 0
fi
done

UPDATE: My local branch is Mybranch in "git push command" and remote branch is refs/for/Mybranch

So even if my branch names are same its giving me error, How can I extract only branch name from remote excluding /refs/for?

Git push command:

git push origin Mybranch:refs/for/Mybranch
Saurabhdv27
  • 39
  • 1
  • 8
  • Remove `else exit 0`. Make sure the name of the hook is precisely `pre-push` and it is executable. – ElpieKay Oct 26 '17 at 12:13
  • Hi this is also giving me error when my branch names are same, because am pushing my change to Gerrit/review branch Thus my Local = Mybranch and Remote= refs/for/Mybranch how can I cut refs/for/ from remote_ref variable? – Saurabhdv27 Oct 26 '17 at 12:48
  • When you push a branch, `local_ref` is `refs/heads/Mybranch` and `remote_ref` is `refs/for/Mybranch`. – ElpieKay Oct 26 '17 at 12:59
  • yeah but I just want to compare Mybranch and Mybranch as local and remote respectively, so am trying: while read local_ref local_sha remote_ref remote_sha do remote_ref >> remote.txt remote_ref1 = cat remote.txt | cut -d'/' -f3 rm remote.txt if [ "$local_ref" != "$remote_ref1" ] then echo " Please check Remote and local branch names"\n exit 1 else exit 0 fi done' – Saurabhdv27 Oct 26 '17 at 13:01

1 Answers1

0

In general, you should not assume refs/heads/ or refs/for/, because your hook will be run for tag pushes (refs/tags/) and other pushes (e.g., refs/notes/, perhaps refs/stash, and so on).

Note that you (or anyone) can run, e.g., git push there refs/heads/master:refs/for/something refs/tags/v1.2:refs/tags/v1.2 refs/remotes/origin/master:refs/heads/master to request a push of three things simultaneously, which is why you have to read all the requests in a loop in the pre-push hook.


You suggested in a comment that you are using:

remote_ref >> remote.txt
remote_ref1 = cat remote.txt | cut -d'/' -f3
rm remote.txt

which has some syntax errors.

It's wiser to check the prefix, and if it's what you expect and wish to handle, strip the prefix. Don't just extract the third word, since that will break if you are using branches named feature/tall, for instance, or are working with references with additional structure beyond the first two components (remote-tracking branches work this way for instance, though normally you would not push them).

In sh/bash script language, you can write, e.g.:

case $local_ref in
refs/heads/*)
    local_type=branch
    local_short=${local_ref#refs/heads/}
    ;;
*)
    local_type=unknown
    ;;
esac

case $remote_ref in
refs/heads/*)
    remote_type=branch
    remote_short=${remote_ref#refs/heads/}
    ;;
refs/for/*)
    remote_type=gerrit
    remote_short=${remote_ref#refs/for/}
    ;;
*)
    remote_type=unknown
    ;;
esac

Now that you have decoded the reference types and found short versions for known cases, you can write your per-case logic, and later extend it as appropriate:

case $local_type,$remote_type in
branch,branch|branch,gerrit)
    # push from branch to branch, or from branch to gerrit:
    # require that the shortened names match exactly (for now)
    if [ $local_short != $remote_short ]; then
        echo "push to $remote_type requires paired names" 1>&2
        echo "but you are pushing from $local_short to $remote_short" 1>&2
        exit 1
    fi
    ;;
*)
    # echo "unknown reference type - allowing" 1>&2 # uncomment for debug
    ;;
esac

All of this would then go inside the main while read ... loop. If you make it to the end of the loop, all the references you are pushing have been verified (since none were rejected by the echo-and-exit code).

torek
  • 448,244
  • 59
  • 642
  • 775
  • Accepted answer. Appreciate your help on this, it worked for me. Just one help, If you can explain how the below extraction works: remote_short=${remote_ref#refs/heads/} – Saurabhdv27 Oct 27 '17 at 09:37
  • The shells have a carefully defined syntax for "variable substitution" or "parameter expansion" (different documentation uses different terms for this). `$var` is the most obvious, but what if you want to expand `$x` followed by the letter `y`? So they have `${x}y` to do that. Inside the braces, they allow further modifications. The details vary from one shell (bash) to another (sh, dash, ksh, etc) but all support `${var#word}` which means "remove leading prefix pattern". There are many more: for bash specifically, see http://wiki.bash-hackers.org/syntax/pe – torek Oct 27 '17 at 14:48
  • Thanks a ton for your help!:) – Saurabhdv27 Oct 30 '17 at 08:36