为什么我的Ruby Git脚本钩子运行错误的$ PATH?

我正在使用RVM。 我为一个项目编写了一个Git pre-commit钩子:

 #!/usr/bin/env ruby puts RUBY_VERSION puts `echo $PATH` exit(1) 

当由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 

它似乎与错误的Ruby版本一起运行,因为$PATH与bash或zsh或sh中的不同。 似乎git正在操纵$PATH 。 手动运行时,我得到:

 $ .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 

在提交钩子的输出中,前面有两个路径,其中一个是/usr/bin ,其中放置了系统Ruby的可执行文件。

这是一种已知行为吗? 我可以以某种方式操纵它吗? 我知道我可以在shebang中指定正确的Ruby版本的完整路径,但这不是我想要的。

我不想使用env而不是使用ruby或rvm包装器的固定路径的原因是这是团队项目而不是团队中的每个人都在使用RVM。

我的最终解决方案是编写自己的包装脚本并将其添加到该项目中。

所有客户端git钩子都存在于$PROJECT/bin/hooks ,所有这些都是ruby脚本。 现在,我只是将那个提到的包装器放在那里,并在$PROJECT/.git/hooks为所有钩子创建了一个包装器的符号链接。

脚本检查是否使用了RVM,如果是,则修复$PATH var,如果项目根目录中有.ruby-version和/或.ruby-gemset文件,则加载相应的版本/ gemset。

然后它将运行相应的ruby脚本如果你感兴趣,这里是包装器:

 #!/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" 

所以,我将获得我的rvm版本/ gemset以及其他所有人在他们的PATH中拥有的ruby版本,每个人都很开心。

你需要将ruby设置为包装器:

 #!$rvm_path/wrappers/ruby-2.0.0-p195/ruby 

您可以使用别名简化它:

 rvm alias create git_hooks 2.0.0-p195 

然后ne shebang看起来像这样:

 #!$rvm_path/wrappers/git_hooks/ruby 

在文件中只需确保用/Users/mgoerlich/.rvm替换$rvm_path ,所以最后它看起来像:

 #!/Users/mgoerlich/.rvm/wrappers/git_hooks/ruby 

我最终做的是: .git文件结构:

  • .git/hooks/pre-commit
  • .git/hooks/pre-commit-main.rb

的.git /钩/预提交:

 #!/usr/bin/env bash export PATH="$THE_GOOD_PATH" ruby "$GIT_DIR/hooks/pre-commit-main.rb" 

的.git /钩/预提交-main.rb的:

 #!/usr/bin/env ruby puts RUBY_VERSION 

然后,当你调用git commit ,确保定义了THE_GOOD_PATH

 export THE_GOOD_PATH="$PATH" git commit 

您还可以从.profile或应用程序的顶层导出THE_GOOD_PATH="$PATH" ,并将符号链接所有挂钩导出到单个文件。

这种方法具有与rbenv无关的优点:它也适用于RVM或Python virtualenv。

我写信给Git开发人员: http ://permalink.gmane.org/gmane.comp.version-control.git/258454要求他们单独留下我们的PATH ,但最初的回复是WONTFIX。