captainhook: $STAGED_FILES is empty during ´git commit -a´ in Docker mode

@renky @ktomk

STAGED_FILES are empty in a ‘commit -a -m’ call if you didn’t add anything before… But nevertheless I’d like to check them in a ‘commit -a -m’ call

In my case I modified two files (js and php) and if I call: git diff-index --diff-algorithm=myers --no-ext-diff --cached --name-status HEAD i get no files

git diff-index --diff-algorithm=myers --no-ext-diff --name-status HEAD shows me the two files…

so the question is, why only look onto the really staged files? From my point of view git commit -a -m is an often used command…

here my output:

$ git status
On branch testbranch
Your branch is ahead of 'origin/testbranch' by 14 commits.
  (use "git push" to publish your local commits)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   app/Http/Controllers/Controller.php
        modified:   resources/js/app.js

no changes added to commit (use "git add" and/or "git commit -a")

now run

$git commit -a -m "testmessage"

all hooks are skipped due to empty STAGED_FILES

What could be the solution - remove --cached option to get all files? Only add files that would be commited with commit -a -> this means only formatter M - so git diff-index would have to be called twice - first time with --cached and all formatters, and second time without --cached but only formatter M

If captain hook would have the possibility to get the commit-attributes, maybe it even could check if commit was called with the -a option and add unstaged modified files in this case?

Another option would also be to add a new Variable - UNSTAGED_FILES additionally to STAGED_FILES - then everybody could decide on his own if he wants to search in both…

EDIT: I made additional tests. I modified a php-File without calling git add. captainhook is running in local run-mode

"config": {
        "verbosity": "verbose"
    },

I added a dump in git/src/Operator/Index.php in Line 205 and dump the result:

$result    = $this->runner->run($cmd, $formatter);
dd($result);
$files     = $result->getFormattedOutput();

When calling git commit -a -m “test” I get the following result:

SebastianFeldmann\Cli\Command\Runner\Result^ {#203
  -cmdResult: SebastianFeldmann\Cli\Command\Result^ {#200
    -cmd: "git diff-index --diff-algorithm=myers --no-ext-diff --cached --name-status HEAD"
    -code: 0
    -validExitCodes: array:1 [
      0 => 0
    ]
    -buffer: array:1 [
      0 => "M\tapp/Models/Model.php"
    ]
    -stdOut: "M\tapp/Models/Model.php\n"
    -stdErr: ""
    -redirectPath: ""
  }
  -formatted: array:1 [
    0 => "app/Models/Model.php"
  ]
}

So it really finds the modified file, although it is not staged already! thats the behaviour I’d expect.

Now I switch to docker run-mode - without changing any other file - still only modified and not staged.:

  "config": {
      "verbosity": "verbose",
      "run-mode": "docker",
      "run-exec": "docker exec -t phpcontainer"
  },

and my dump gives me this:

SebastianFeldmann\Cli\Command\Runner\Result^ {#202
  -cmdResult: SebastianFeldmann\Cli\Command\Result^ {#199
    -cmd: "git diff-index --diff-algorithm=myers --no-ext-diff --cached --name-status HEAD"
    -code: 0
    -validExitCodes: array:1 [
      0 => 0
    ]
    -buffer: []
    -stdOut: ""
    -stdErr: ""
    -redirectPath: ""
  }
  -formatted: []
}

so the same situation, one time local, one time docker gives different result. What I don’t understand: If I call the command

git diff-index --diff-algorithm=myers --no-ext-diff --cached --name-status HEAD

directly on the bash it ALLWAYS doesn’t give me any result - so I don’t understandy why in the first case (local) it really finds any file…

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 31

Commits related to this issue

Most upvoted comments

This is now fixed with version 5.18.0

If the run-git option is set. The Captain can use the provided path to the.git directory to map the path to the index file. So für prepare-commit-msg and pre-commit hooks the env var is now added automatically to the hook script.

Big thanks to @renky for the support and the GIT_INDEX_FILE insight.

@sebastianfeldmann can you please change the issue title and add " in docker mode" at the end to have a better description?

thats the original reason why i switched from local to docker-mode…

This is pretty straight and I get that angle now. I always forget about symfony console as I for myself drop it where I can as it creates so many implications with PHP tooling, the symfony projects don’t have good portability. Anyway, it makes the docker mode mandatory.

It’s only happening in docker mode

The GIT_INDEX_FILE environment parameter also needs to be passed into the docker container (-e GIT_INDEX_FILE) and the contents must map with the container file-system (/E: IIRC the suggestion by torek was with the working directory, so it should be relatively easy to do that: -w ...)

Testing unstaged files would be a bad idea, because if the user is not committing the files why check them.

You are right in local run mode the Cap’n detects the changed files and $STAGED_FILES is not empty after calling git commit -a. And that is expected since -a should change the index before executing the commit. It seems the docker version is running into another git issue that gets ignored. That would explain the empty STAGED_FILES.

What you could do to debug this locally is to remove the try catch block in vendor/sebastianfeldmann/git/src/Operator/Index.php:274

private function isHeadValid(): bool
{
    try {
        $cmd    = new GetCommitHash($this->repo->getRoot());
        $result = $this->runner->run($cmd);
        return $result->isSuccessful();
    } catch (RuntimeException $e) {
        // if we do not have a permission error the current head is just invalid
        if ($e->getCode() !== 128) {
            return false;
        }
        throw $e;
    }
}
private function isHeadValid(): bool
{
    $cmd    = new GetCommitHash($this->repo->getRoot());
    $result = $this->runner->run($cmd);
    return $result->isSuccessful();
}

Then run the `git commit -a -m “foo” again and see if you get any errors