Search code examples
windowsgitvagranthooknfs

git commit -am "Commit message" doesn't work properly with vagrant machine


I am using Git Bash in Windows 7. For my project I installed VirtualBox and Vagrant on Windows. In my home directory there are some project folders which are synced into the vagrant machine based on nfs. So Vagrant will keep the files synchronous.

The box is a webserver based on debian/contrib-jessie64 with some configurations like Git for several packages to be installed via Composer. Git is for BitBucket purposes only because some packages need an ssh permission. But Git itself is never used by me within the box because it's very slow. Furthermore Git is required to listen to several hooks. The webserver does have PHP and Composer installed but my host machine (Windows) does not. The reason why I didn't install all the stuff on Windows is the circumstance to keep all versions the same on both host and guest machines. I do want the server do all the php stuff for me and that's fine.

So, working with Git on Windows requires git hooks to be configured on Windows as well as for the box. All the hooks, which are listening to changes on Windows, execute the corresponding hook within the vagrant box. All arguments are piped of course.

This is my pre-commit file on Windows

#!/usr/bin/env bash
coreDirectory="$HOME/projects/foo"

arguments=""

for arg in "$@"
do
    arguments="$arguments $arg"
done

cd $coreDirectory && vagrant ssh -c "cd /home/projects/foo && 
./.git/hooks/pre-commit $arguments"

This works fine. The pre-commit file in the box is being executed and triggers a special Executor which calls the ./vendor/bin/phpcs file for code sniffing.

I only want to trigger the code sniffing rules on staged files, so all modified or untracked files which have been added to stage area should be sniffed. This also works fine. The Executor prepares all files with the following command:

git -C /home/projects/foo diff --name-only --diff-filter=AM --cached

In Windows adding desired files to staged area with git add --all and committing them works properly and the pre-commit hook triggers the pre-commit hook in the box which triggers the CodeSniffer.

But using git commit -am "Foo bar" does not work properly with the command above. The hook reacts but the Executor command within the machine, which tries to get the --cached files, returns an empty set.

I assume that either the vagrant box isn't fast enough to move the changed files to the staged area after I have used the git commit -am command on Windows or the command git commit -am doesn't even move files to staged area.

Do you have any ideas?


Solution

  • When you use git commit -a, Git builds a new and temporary index to hold the files to be committed. The existence of this new temporary index is communicated through an environment variable, GIT_INDEX_FILE.

    When you use ssh to run commands on another machine (even though it's a VM, it's another machine for this purpose), that other machine does not receive the GIT_INDEX_FILE setting, so it uses the normal everyday index. That index has no changes in it, so the behavior you are seeing is correct: in fact, nothing is staged.

    Note that the contents of an index file differ on Windows and Linux (Git stores nearly-raw stat system call data), so it's generally unwise to attempt to share index files across hosts this way. In fact, Virtualbox shared folders have a number of ... features? bugs? misfeatures? whatever you want to call them, things that fare poorly in Git environments. I find it much more reliable to treat each VM as a truly separate machine, using the shared-folder feature as minimally as possible, and in particular never using it to store in-progress work with Git.