Git适用于网站 / post-receive / 测试和生产站点的分离

5
我使用Git来管理我的网站源代码和部署,并且目前在同一台服务器上运行测试和正式站点。参考这篇文章http://toroid.org/ams/git-website-howto,我编写了以下post-receive钩子脚本,以区分推送到我的正式站点和测试站点的情况:
while read ref
do
  #echo "Ref updated:"
  #echo $ref -- would print something like example at top of file
  result=`echo $ref | gawk -F' ' '{ print $3 }'`
  if [ $result != "" ]; then
    echo "Branch found: "
    echo $result
    case $result in
      refs/heads/master )
        git --work-tree=c:/temp/BLAH checkout -f master
        echo "Updated master"
        ;;
      refs/heads/testbranch )
        git --work-tree=c:/temp/BLAH2 checkout -f testbranch
        echo "Updated testbranch"
        ;;
      * )
        echo "No update known for $result"
        ;;
    esac
  fi
done
echo "Post-receive updates complete"

然而,我对这样做是否真的安全存有疑虑 :) 我绝不是Git专家,但我猜测Git可能会跟踪当前检出的分支头,并且这种方法可能有潜力令它感到困惑。

因此,有几个问题:

  1. 这样做安全吗?

  2. 是否有更好的方法:将我的基础仓库作为测试站点仓库(带相应的工作目录),然后让该仓库将更改推送到新的线上站点仓库,其具有相应的工作目录以适配线上站点基础?这样还可以让我将生产环境移到另一台服务器并保持部署链完整。

  3. 是否有我忽略的内容?使用Git管理网站时,是否有不同的、清晰的方法来区分测试和生产环境?

另外,在Vi的答案下,是否有一个很好的方法来处理删除而不会大量干扰文件系统?

谢谢, -Walt

PS-我想到的用于多个仓库(除非我听到更好的建议)的脚本如下:

sitename=`basename \`pwd\``

while read ref
do
  #echo "Ref updated:"
  #echo $ref -- would print something like example at top of file
  result=`echo $ref | gawk -F' ' '{ print $3 }'`
  if [ $result != "" ]; then
    echo "Branch found: "
    echo $result
    case $result in
      refs/heads/master )
        git checkout -q -f master
        if [ $? -eq 0 ]; then
            echo "Test Site checked out properly"
        else
            echo "Failed to checkout test site!"
        fi
        ;;
      refs/heads/live-site )
        git push -q ../Live/$sitename live-site:master
        if [ $? -eq 0 ]; then
            echo "Live Site received updates properly"
        else
            echo "Failed to push updates to Live Site"
        fi
        ;;
      * )
        echo "No update known for $result"
        ;;
    esac
  fi
done
echo "Post-receive updates complete"

然后在 ../Live/$sitename 的仓库中(这些是“裸”仓库,在初始化后添加工作树),有一个基本的 post-receive 脚本:

git checkout -f
if [ $? -eq 0 ]; then
    echo "Live site `basename \`pwd\`` checked out successfully"
else
    echo "Live site failed to checkout"
fi

目前我采用了第二种方法,到目前为止看起来还不错。只要我在推送到实际网站后记得切换回测试代码库的主分支即可保持清晰整洁。 - Walt W
3个回答

2

认为两种方法都可以。

您还可以使用“git archive master | tar -C c:/temp/BLAH -x”和“git archive live-site | ssh live-site 'tar -C /var/www -x'”。

保持分离的存储库可能很有用,但是“在另一个与推送相关的挂钩内进行推送”看起来很棘手,我预计它会很慢。这是一种缓慢而脆弱的长链。

也许在测试“测试”版本后应手动触发现场更新?


打包成tar文件可能是个好主意;我下周一定会研究一下。但是,我不太确定它的可行性,因为我是通过msysGit运行脚本的。但是,它们似乎已经预装了tar,所以也许可以。 - Walt W
好的 - 这里有一个关于这个答案的问题 - 我喜欢打包的概念,但有一个不令人满意的部分 - 我希望更新尽可能无缝。多个repo技巧的好处之一是,虽然棘手,但文件系统仅根据每个提交的增量进行更改 - tar方法则需要rm -rf删除部署目录,然后提取tar......也许有一个tar标志我不知道?tar方法在许多方面都很好,但我认为在我的主机上删除更新之间的所有内容是有风险的。 - Walt W
那么你可能应该使用单独的存储库。但我仍然认为,将代码推送到某个特殊的引用(ref)不应该自动更新生产网站。这只是不应该那么容易。 - Vi.
使用“git checkout”更新网站本身并不是原子操作。如果有用户在“checkout”的同时访问该网站,会发生什么?您可以将网站提取/checkout到其他目录,并将网站的配置文件指向使用该其他目录。 - Vi.
仓库中存储了哪些文件?是一些小的相互关联的PHP文件,还是大的独立块? - Vi.
Vi - 我同意这不应该那么容易,但请考虑包含要推送到实时站点的分支的存储库可能是私有存储库 - 不一定是公共副本。关于您提出的其他问题 - 是的,git checkout 不是原子操作,但其影响比一般的 tar 命令更受限制。就存储在存储库中的文件而言,它们大多是一堆小东西。 - Walt W

1

我也按照toroid.org上的指南进行了操作,但是我想指出的是,虽然您从一个裸仓库开始,但是通过添加工作目录,很可能需要额外的处理。如果您有可能动态或以其他方式更改内容并且不希望在使用git checkout -f时丢失数据,则会发现以下钩子非常有用:

pre-receive

#!/bin/sh
git add -A
git diff --quiet --cached
if [ $? -gt 0 ]; then
    git commit --quiet -m "autocommit"
    echo "Working Directory was out of sync. Pull to receive updated index."
    exit 1
fi

如果远程工作目录中有更改,这将停止推送。可以将其视为某人(Web服务器)进行更改但忘记提交它们。使用checkout-f将放弃这些更改。这个钩子是防止这种情况发生的好地方,但如果在拉取之前也有一个钩子在远程服务器上调用,那么您将无缝地接收这些更改,这将是很好的。

post-receive

#!/bin/sh
git checkout -f
echo "Working directory synced."

关于有两个分支的问题,我认为你的第一个解决方案比处理多个存储库更优雅。如果你真的想保持生产站点的隔离,你可以在本地使用类似增量打补丁的rsync。我会在仓库中有一个测试和稳定的分支,只有测试站点作为工作目录。准备发布时,将测试合并到稳定分支,推送,并设置一个钩子来查找提交到稳定分支的调用rsync的操作。

+1 对于 pre-receive 评论 - 非常有用的提示,谢谢。关于多个仓库,在实际中并不是太糟糕 :) rsync 绝对是另一个可行的选择。谢谢! - Walt W
git add . 没有捕捉到所有的更改(删除),已更改为 git add -A - tcp

1
更好的方法是将我的基本存储库作为测试站点存储库(具有相应的工作目录),然后让该存储库将更改推送到新的实时站点存储库,该存储库具有与实时站点基础相对应的工作目录。这也允许我将生产环境移动到不同的服务器并保持部署链完整。
是的,绝对是这样。很少有情况需要将测试站点托管在生产站点旁边。这几乎在所有方面都是危险和不专业的,更不用说数据库损坏、Web服务器锁定等问题了。
我通常会设置一个虚拟机进行测试。效果非常好,而且我可以在旅行时随身携带它。
使用git部署网站是一个非常好的想法,有很多其他人也这样做(例如Rob Conery)。如果您已经有一个实时和测试站点,那么您应该在存储库中为它们设置单独的分支,并将其设置为相应服务器存储库上的远程跟踪分支。您的工作流变得非常简单,只需在测试分支中进行工作,将其推送到测试,测试它,合并到实时并推送实时。
老实说,不要让自己太难了。

这听起来有点像可行的方向 / 上周效果还不错。 - Walt W

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接