Ruby on rails 如何通过git push将多个分支部署到不同的目录?

Ruby on rails 如何通过git push将多个分支部署到不同的目录?,ruby-on-rails,git,Ruby On Rails,Git,在生产中,我维护两个站点-beta和release。每个都通过软链接指向不同的目录(例如) 我是svn的长期用户,正在使用git。我习惯于通过svn更新部署和更改新分支上的软链接,事情非常简单 现在我要转到git。我仍然需要两个软链接(这是一个使用Passenger的Rails应用程序),不过现在我希望它们指向两个不同的git分支(“beta”和“release”)。我希望能够通过git push(或git pull)更新它们 问题1:我不确定最好的方法 我开始这样做的方式是只部署到两个不同的远

在生产中,我维护两个站点-beta和release。每个都通过软链接指向不同的目录(例如)

我是svn的长期用户,正在使用git。我习惯于通过svn更新部署和更改新分支上的软链接,事情非常简单

现在我要转到git。我仍然需要两个软链接(这是一个使用Passenger的Rails应用程序),不过现在我希望它们指向两个不同的git分支(“beta”和“release”)。我希望能够通过git push(或git pull)更新它们

问题1:我不确定最好的方法

我开始这样做的方式是只部署到两个不同的远程设备,例如

git push ssh://scott@x.com/home/scott/myapp-beta beta
git push ssh://scott@x.com/home/scott/myapp-release release
但这不起作用,因为默认情况下推送不会更新工作树

因此,我进入远程目录并运行git reset——第一次很难,它会拉动工作树。但是我再推一次,我无法得到新的推动-它只是停留在最初的一个

(顺便说一句,请注意,我似乎无法推到“myapp beta.git”-如果失败,我必须推到目录名。我担心这是问题的一部分,但我不知道我在这里做错了什么。)

所以,如果问题1的答案是我的方法很好,问题2:我实际做的有什么问题?如果有我应该用的钩子,有人能指给我看吗

(对问题1的回答是“运行这七个手动步骤”并不是一个非常有用的答案,因为svn checkout+ln-s是两个步骤。)

谢谢。我想继续写代码。

这篇文章对一个类似的问题进行了有趣的讨论

其解决方案和结论之一涉及:

  • 生产服务器上的裸存储库
  • 一个克隆的存储库,带有一个钩子,可以将推到裸存储库中的内容拉出来
所以在你的情况下

  • 一个简单的回购协议,你可以在上面推测试版和发布分支
  • 两个克隆的回购“beta”和“release”,用钩子从裸回购中拉出各自的分支
简而言之:一步:
gitpush
。不再需要管理链接(因为目录不再代表Git中的分支,与SVN不同)


关于挂钩部分,裸回购协议中的a可能就是你所需要的

注:

post receive
钩子以设置为
repo/.GIT
文件夹的
GIT\u DIR
环境变量开始,因此无论您将“
cd
”放入哪个路径,都将始终尝试在那里运行任何以下GIT命令。
解决这个问题只需取消设置
GIT\u目录


:它完全忽略继承的环境,只使用提供的变量和值。

我使用类似的
post receive
来发布我的网站,因为Git在推送时不接触工作目录。远程存储库是非裸存储库,即它有一个工作目录

if [ -n $GIT_DIR ]; then
    # Current dir is "<reporoot>/.git/", but we need to run reset at "<reporoot>/".
    # Clearing GIT_DIR is needed, or reset will fail with "fatal: Not a git repository: '.'"
    unset GIT_DIR
    cd ..
fi
git reset --hard
if[-n$GIT_DIR];然后
#当前目录为“/.git/”,但我们需要在“/”处运行重置。
#需要清除GIT_DIR,否则重置将失败并显示“致命:不是GIT存储库:”
未设置GIT_目录
光盘
fi
git重置——硬

(顺便说一句,请注意,我似乎无法推到“myapp beta.git”-如果失败,我必须推到目录名。我担心这是问题的一部分,但我不知道我在这里做错了什么。)


创建没有工作目录的裸Git存储库(
Git init--bare
)时,通常将目录命名为“something.Git”。当拥有非裸存储库时,存储库实际上位于“.git”子目录中,因此完整路径为“something/.git”。似乎在这两种情况下,您都可以省略“.git”部分,git将自动检测到它。

我并不反对其他解决方案,但我认为有一种不太老练的“git方式”可以做到这一点。下面是我要做的:

  • 在我的服务器上,我设置了一种集中式存储库(由Gitosis或类似的东西管理)
  • 从客户端开始,我会不断地从存储库中提取、进行更改和回退。分支机构当然是自动管理的
  • 我会将所需的分支从Gitosis拉入服务器的public_html/beta_public_html。我会使用Cron作业定期与Gitosis保持同步。如果您不喜欢Cron作业的想法,您可以像其他人指出的那样使用某种hook+脚本

  • 解决方案是推送到单个存储库,该存储库将采用
    update
    post-receive

    有几种不同的方法可以创建两个签出,可以在hook(服务器上)中使用。从最轻的开始:

    • 如果您不需要这两个签出目录(签出版本)实际上是git存储库,那么只需使用导出两个快照(两个分支)

      其中,“master”和“devel”是您希望签出的分支的名称。请注意,严格来说,
      --format=tar
      不是必需的,因为tar格式是“git归档”的默认格式。您可能还希望删除旧内容(“
      rm-rf public_html/”
      ,在第一行“
      tar xf-
      ”之前,加上“
      &&&
      ”,第二行也是如此)

      导出文件的另一种方法是使用低级命令“
      git read tree
      ”(将树写入索引)和“
      git checkout index
      ”(将文件从索引复制到工作区)

      在这个解决方案中,您推入的存储库可以(而且应该)是空的,即没有工作目录本身

    • 另一个解决方案是,您推入的存储库中有两个工作目录,可以使用
      c中的脚本创建
      
      $ cd bare
      $ chmod +x .git/hooks/post-receive
      
      with a post-receive hook like
      
      #!/bin/sh
      cd ../../beta
      env -i git reset --hard
      cd ../../release
      env -i git reset --hard
      
      if [ -n $GIT_DIR ]; then
          # Current dir is "<reporoot>/.git/", but we need to run reset at "<reporoot>/".
          # Clearing GIT_DIR is needed, or reset will fail with "fatal: Not a git repository: '.'"
          unset GIT_DIR
          cd ..
      fi
      git reset --hard
      
       git archive --format=tar --prefix=public_html/ master | (cd /var/www/html && tar xf -)
       git archive --format=tar --prefix=beta_public_html/ devel | (cd /var/www/html && tar xf -)