Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In pre-push hook, get "git push" command full content?

When a Git pre-push hooks script is working, how to get the full git push command content?

Example, when I run: git push origin master, pre-push hooks executed.
I want to get origin & master in this hook.

How can I get the list of arguments?

like image 932
Shaun Avatar asked Feb 25 '17 11:02

Shaun


People also ask

What is git pre Push hook?

Git Git Client-Side Hooks Git pre-push hook pre-push script is called by git push after it has checked the remote status, but before anything has been pushed. If this script exits with a non-zero status nothing will be pushed.

Do git hooks get pushed?

No. Hooks are per-repository and are never pushed.

How do git pre-commit hooks work?

The pre-commit script is executed every time you run git commit before Git asks the developer for a commit message or generates a commit object. You can use this hook to inspect the snapshot that is about to be committed.

How do you do a pre-commit hook?

Open a terminal window by using option + T in GitKraken Client. Once the terminal windows is open, change directory to . git/hooks . Then use the command chmod +x pre-commit to make the pre-commit file executable.


1 Answers

TL;DR summary: you need a while loop

Your hook script (assuming sh/bash) should include a loop of the form:

while read localname localhash remotename remotehash; do
    ... code here using $localname etc ...
done

Description

All of the Git hooks are described in the githooks page. The pre-push hook description begins with:

This hook is called by git push and can be used to prevent a push from taking place. The hook is called with two parameters which provide the name and location of the destination remote, if a named remote is not being used both values will be the same.

Information about what is to be pushed is provided on the hook’s standard input with lines of the form:

<local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF

For instance, if the command git push origin master:foreign were run the hook would receive a line like the following:

refs/heads/master 67890 refs/heads/foreign 12345

although the full, 40-character SHA-1s would be supplied. ...

The first paragraph means that in a shell script, $1 and $2 are the name of the remote—e.g., origin—and its URL, or the URL repeated twice if the user ran:

git push https://some.host.name/some/path ...

The second paragraph is important. A git push command can push more than one branch. For instance, I can run:

git push origin feature-A feature-B

to push both feature-A and feature-B. You must read all input lines, one line at a time, to discover what is to be pushed. The current branch in the repository is not important: reading HEAD will give you the wrong answer unless the user happens to be pushing the current branch. On the other hand, most users mostly just push the current branch. This will give you the illusion that your hook is 100% reliable, when it's actually only 92.37% reliable.1

As the documentation notes, the hook gets the full name of each reference. If you are pushing a branch, that full name starts with refs/heads/, but you can push a tag, in which case the full name starts with refs/tags/. To write a reliable hook, you must inspect the full name, rather than simply stripping off the first two components.2


1Like 38.61% of statistics, this one was made up on the spot. :-)

2There are a lot of bad sample hooks (not all of them pre-push hooks) out there that use:

branch=$(echo $ref | cut -d/ -f3)

If you are pushing tag v2.3, this hook will think you are pushing a branch named v2.3. If you are pushing a branch named bugfix/1234, it will think you are pushing a branch named bugfix! The cut technique is just wrong, but a quick fix for the latter is to use -f3-, which at least produces bugfix/1234. It's better to verify the first components of the ref—i.e., do something like:

case $ref in
refs/heads/*) ... it's a branch ...;;
refs/tags/*) ... it's a tag ...;;
*) ... it's something else entirely, such as refs/notes/* ...;;
esac

Once you know the prefix, you can use ${ref#refs/heads/} or ${ref#refs/tags/} to strip off the known prefix and get the full but unqualified branch or tag name. If many cases, though, you can just work directly with the full reference name.

like image 63
torek Avatar answered Oct 11 '22 17:10

torek