Jatin Dhoot
Jatin Dhoot

Reputation: 4364

git clone different repository in git hooks creating trouble

We have a specific requirement in which we have to push all files which arrive for being committed to a certain branch.

We are planning to achieve this via git hooks specifically commit-msg hook.

While doing so what we do is we clone branch to temporary location (/tmp/) and then in git commit-msg hook, attempt to commit arrived files to certain branch.

But what happens now is we see all files as deleted in /tmp/.

Crude commit-msg script is as under:-

#!/bin/bash
#
#!/usr/bin/env bash

#git config credential.helper store
REPOSRC="https://<USER>:<PASS>@<REPO_URL>"
LOCALREPO="<LOCAL_REPO_DIR>"

echo "Pulling code to temporarry location";

cd /tmp && git clone "${REPOSRC}" || (cd "${LOCALREPO}"; git pull;)

#here when I navigate to /tmp/<LOCALREPO> all files are listed as DELETED

git diff --cached --name-status | while read st file; do

    echo "file == $file and status == $st";

                    if [ "$st" == "A" ]; then
                        cd "${LOCALREPO}" && git add "$file" && git commit "$file" -m "$COMMIT_MSG" && git push origin "$branch"
                    else
                        cd "${LOCALREPO}" && git commit "$file" -m "$COMMIT_MSG" && git push origin "$branch"
                    fi
done

What can be the root cause for this?

EDIT:

GIT_INDEX_FILE shows path of index file from which commit was initiated and not /tmp/ path. Is there any way to change this variable? Also index file prints something like next-index-32419.lock. Regards

Upvotes: 8

Views: 1763

Answers (3)

anthony sottile
anthony sottile

Reputation: 69964

I ran into this same issue while developing pre-commit (which distributes git hooks as installable git repositories).

The GIT_* environment variables are interfering with the git clone commands. These environment variables are set by git internals before invoking the .git/hooks/pre-commit script.

My solution to this was to clear all GIT_* environment variables (except for a whitelist of allowed variables).

My solution is in python but you can probably adapt it into whatever language you're writing in:

def no_git_env(_env=None):
    # Too many bugs dealing with environment variables and GIT:
    # https://github.com/pre-commit/pre-commit/issues/300
    # In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running
    # pre-commit hooks
    # In git 1.9.1 (maybe others), git exports GIT_DIR and GIT_INDEX_FILE
    # while running pre-commit hooks in submodules.
    # GIT_DIR: Causes git clone to clone wrong thing
    # GIT_INDEX_FILE: Causes 'error invalid object ...' during commit
    _env = _env if _env is not None else os.environ
    return {
        k: v for k, v in _env.items()
        if not k.startswith('GIT_') or
        k in {'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND'}
    }

Upvotes: 1

Tarun Lalwani
Tarun Lalwani

Reputation: 146530

I would just simply execute my git commands in a clean environment. Now the question is how to do that?

$ env --help | grep env
Usage: env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
Set each NAME to VALUE in the environment and run COMMAND.
  -i, --ignore-environment  start with an empty environment
  -u, --unset=NAME     remove variable from the environment
A mere - implies -i.  If no COMMAND, print the resulting environment.
Full documentation at: <http://www.gnu.org/software/coreutils/env>

So using a -i would give your git command a clean environment. But you might need certain variables to exists. So I would just add below to the top of my script

alias git='env -i PATH=$PATH HOME=$HOME git'

Now all the git commands your run in your hook will not inherit the environment which the commit hook was run with

Upvotes: 0

VonC
VonC

Reputation: 1324935

Whenever a hook changes folder, it is important to check the value of:

  • GIT_DIR (which should reference the right .git repo folder in your case)
  • GIT_WORK_TREE (which should not reference the expected folder)

That is why, for any Git command, you would need to replace git with:

git --work-tree=$(pwd) ...

(or /path/to/your/working/tree)

Upvotes: 5

Related Questions