edjm
edjm

Reputation: 5472

I need some guidance with my Git hook for pre-commit using Bash

Okay what I am attempting to do for our project is to have the developer choose if they want to commit or compile and then commit their code. This is because we have a code formatter that cleans up everything and currently on deployments many are not compiling first before their merge request. So, by having this file pushed onto all of the projects they will be reminded and have to pick one.

Currently the problem is trying to call the maven build at the moment. I cannot do a cd ../../ up to the project root folder. Suggestions on how to get this to work? Please I don't want to have a debate or discussion over why this was decided I just need to be pointed in the direction of how to get this to work. Thanks.

echo "CC to Compile and Commit"    "C to just compile"

while true; do
  read choice

  echo "Your choice was " $choice
  if ( "$choice" == CC" ) ; then
    cd ../../
    if [ mvn compile ] ; then
      echo "Compile was okay."
      echo "Continue with git commit."
    fi
  fi
  break
done

Upvotes: 2

Views: 982

Answers (3)

torek
torek

Reputation: 487993

Without addressing either maven, or whether this is a reasonable thing to be doing in a pre-commit hook, there are several points to consider here:

  • Git hooks are run in some directory.

    The precise current-working-directory for the hook varies. If git commit is run anywhere within the repository tree, the pre-commit hook itself runs in the top level of the Git repository. This is true regardless of which sub-directory you are in:

    $ cat .git/hooks/pre-commit
    #! /bin/sh
    echo precommit: pwd = $(pwd)
    exit 1
    $ git commit
    precommit: pwd = [snip]/git
    $ cd Documentation
    $ git commit
    precommit: pwd = [snip]/git
    

    Note that this was not .../git/Documentation despite the fact that I was in the Documentation sub-directory.

    If git commit is run elsewhere, the current working directory may not be the top level of the repository, and may in fact be entirely unrelated to the repository itself, or the work-tree:

    $ cd /tmp
    $ git --git-dir=$HOME/src/kernel.org/git/.git commit
    precommit: pwd = /tmp
    

    It is therefore vital to: (1) constrain the location where git commit is run, or (2) avoid using the current working directory at all. I put this in bold because of the third point below. However, if you like, you can treat the current working directory as the work-tree: there is no need to attempt to cd ../.. out of the .git/hooks directory.

  • The standard input of a Git hook is often not connected to the user's terminal—assuming there is a user and a terminal in the first place. For example:

    $ cat .git/hooks/pre-commit
    #! /bin/sh
    if [ -t 0 ]; then
        echo precommit: stdin is a tty
    else
        echo precommit: stdin is NOT a tty
    fi
    exit 1
    $ git commit
    precommit: stdin is NOT a tty
    

    While you can attempt to open /dev/tty, this will only work if there is a /dev/tty to open, so there is a risk here.

  • During a git commit, the contents of the work tree are not the contents that will be committed. What will be committed is whatever is in the index. Examining the work-tree is only correct if the index matches the work-tree. You can test for this using the require_clean_work_tree shell function in git-sh-setup, which is in the git --exec-path, and git --exec-path has been added at the front of $PATH, so you can simply run:

    . git-sh-setup
    require-clean-work-tree "commit" "message to emit if work tree is not clean"
    

    for instance (the two arguments are the action and the message to produce on failure).

That said, the other issue you found is that:

[ expression ]

is the syntax to run the [ command, passing it expression ] as its parameters. (The [ command is also known as the test command; when invoked as test <expression> it does not demand a final ] argument, and otherwise works the same as when run as [.) You wanted to run the mvn command, not the [ or test command.

Upvotes: 1

Olli K
Olli K

Reputation: 1760

A nice way to create menus in bash is with the select command, here's an example (assumed to be run somewhere in the project directory):

#! /bin/bash

cmds=("Commit" "Compile and commit")
select cmd in "${cmds[@]}"; do
    pushd "$(git rev-parse --show-toplevel)"
    echo "You picked $cmd, working dir changed to $(pwd)"
    if [[ $cmd == "Compile and commit" ]]; then
        mvn compile
        if [[ $? != "0" ]]; then
            echo "Something went wrong"
        else
            echo "Compilation ok!"
        fi
    fi
    #git commit
    popd
    echo "Done, working dir now $(pwd)"
    break
done

Upvotes: 1

Slawomir Jaranowski
Slawomir Jaranowski

Reputation: 8497

Please use:

if ( mvn compile ) ; then

[ is for runing test command in really

Upvotes: 1

Related Questions