可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm using RVM. I wrote a Git pre-commit
hook for a project:
#!/usr/bin/env ruby
puts RUBY_VERSION
puts `echo $PATH`
exit(1)
which outputs this when run by Git:
$ git ci -m 'foo'
1.8.7
/usr/libexec/git-core:/usr/bin:/usr/local/heroku/bin:/Users/mgoerlich/.rvm/gems/ruby-2.0.0-p195@global/bin:/Users/mgoerlich/.rvm/rubies/ruby-2.0.0-p195/bin:/Users/mgoerlich/.rvm/bin:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/platform-tools:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/tools:/usr/local/bin:/usr/local/sbin:/Users/mgoerlich/.dotfiles/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/bin/core_perl:/Users/mgoerlich/bin:/usr/local/share/npm/bin:/usr/local/share/npm/bin
It seems to run with the wrong version of Ruby because $PATH
is not the same as in bash or zsh or sh. It seems like git is manipulating $PATH
. When run manually, I get this:
$ .git/hooks/pre-commit
2.0.0
/usr/local/heroku/bin:/Users/mgoerlich/.rvm/gems/ruby-2.0.0-p195@global/bin:/Users/mgoerlich/.rvm/rubies/ruby-2.0.0-p195/bin:/Users/mgoerlich/.rvm/bin:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/platform-tools:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/tools:/usr/local/bin:/usr/local/sbin:/Users/mgoerlich/.dotfiles/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/bin/core_perl:/Users/mgoerlich/bin:/usr/local/share/npm/bin:/usr/local/share/npm/bin
In the output of the commit hook, there are two paths prepended, one of them /usr/bin
where the system Ruby's executable is placed.
Is this a known behavior? Can I manipulate that somehow? I know I could specify the full path to the correct Ruby version in the shebang, but this is not what I want.
回答1:
The reason i didn't wanted to use env
instead of a fixed path to ruby or a rvm wrapper was that this is for a Team Project and not everyone in the Team is using RVM.
My final solution was to write my own wrapper script an add it to that project.
All client-side git hooks 're living in $PROJECT/bin/hooks
, all of them ruby scripts.
Now, i've just put that mentioned wrapper in there, and created a symlink to that wrapper in $PROJECT/.git/hooks
for all the hooks.
The script check's if RVM is used and if so fixes the $PATH
var and if there are .ruby-version
and/or .ruby-gemset
files in the project root it loads the according version/gemset.
Then it'll run the according ruby script
Here's the wrapper in case you're interested:
#!/bin/bash
if [ -d "$HOME/.rvm/bin" ]; then
PATH="$HOME/.rvm/bin:$PATH"
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
if [ -f ".ruby-version" ]; then
rvm use "$(cat .ruby-version)"
fi
if [ -f ".ruby-gemset" ]; then
rvm gemset use "$(cat .ruby-gemset)"
fi
fi
ruby "bin/hooks/$(basename "$0").rb"
So, i'll get my rvm version/gemset and everybody else the ruby version they have in their PATH, and everyone is Happy.
回答2:
you need to set ruby to a wrapper:
#!$rvm_path/wrappers/ruby-2.0.0-p195/ruby
You can simplify it with an alias:
rvm alias create git_hooks 2.0.0-p195
And then the ne shebang will look like this:
#!$rvm_path/wrappers/git_hooks/ruby
In the file just make sure to replace $rvm_path
with /Users/mgoerlich/.rvm
so finally it looks like:
#!/Users/mgoerlich/.rvm/wrappers/git_hooks/ruby
回答3:
What I ended up doing is: the .git
file structure:
.git/hooks/pre-commit
.git/hooks/pre-commit-main.rb
.git/hooks/pre-commit:
#!/usr/bin/env bash
export PATH="$THE_GOOD_PATH"
ruby "$GIT_DIR/hooks/pre-commit-main.rb"
.git/hooks/pre-commit-main.rb:
#!/usr/bin/env ruby
puts RUBY_VERSION
Then, when you call git commit
, make sure that THE_GOOD_PATH
, is defined:
export THE_GOOD_PATH="$PATH"
git commit
You could also export THE_GOOD_PATH="$PATH"
from your .profile
or the toplevel of your application and symlink all hooks to a single file.
This method has the advantage of being rbenv agnostic: it also works with RVM or Python virtualenv.
I wrote to the Git developers at: http://permalink.gmane.org/gmane.comp.version-control.git/258454 asking them to leave our PATH
alone, but the initial reply was WONTFIX.