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

时间:2009-09-23 06:03:06

标签: ruby-on-rails git

在制作中,我维护了两个网站 - 测试和发布。每个都通过软链接指向不同的目录(例如)

beta_public_html -> /home/scott/myapp/trunk/public
public_html      -> /home/scott/myapp/branches/1.2.3/public

我是一个长期的svn用户,转向git。我习惯通过svn update部署并更改新分支上的软链接,事情很简单。

现在我要转向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

但这不起作用,因为默认情况下push不会更新工作树。

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

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

所以,如果问题1的答案是我的方法没问题,问题第2部分:我实际上做了什么错了?如果有我应该使用的钩子,有人可以指向我吗?

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

感谢。我想回到编写代码。

4 个答案:

答案 0 :(得分:3)

文章Git push is worse than worsless对类似问题进行了有趣的讨论。

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

  • 生产服务器上的裸存储库
  • 一个克隆的存储库,带有一个钩子,用于拉动已被推入裸机的

所以在你的情况下,

  • 一个可以推送测试版和发布分支的裸仓库
  • 两个克隆的回购'beta'和'release'带有一个钩子,从裸露的仓库中拉出各自的分支。

简而言之:一步:git push。没有更多的管理链接(因为该目录不再代表Git中的分支,与SVN不同)


关于钩子部分,裸仓库中的post-receive hook可能就是你需要的全部

请参阅Git Tip: Auto update working tree via post-receive hook

$ 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

注意:

  

post-receive挂钩开始时GIT_DIR环境变量设置为repo/.git文件夹,因此无论您在哪个路径'cd',它都会尝试在那里运行任何以下的git命令   解决这个问题只是取消设置GIT_DIR

'env -i' does just that:它完全忽略了继承的环境,只使用提供的变量和值。

答案 1 :(得分:2)

解决方案是推送到单个存储库,该存储库将使用updatepost-receive hook

创建两个签出有几个单独的可能性,可以在钩子(在服务器上)使用。从最轻量级开始:

  • 如果您不需要将这两个已检出的目录(已检出的版本)实际成为git存储库,则只需使用git-archive 导出两个快照(两个分支)

     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 -)
    

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

    导出文件的替代方法是使用低级命令“git read-tree”(将树写入索引)和“git checkout-index”(将文件从索引复制到工作区)。 / p>

    在此解决方案中,您推入的存储库可以(并且应该)是裸的,即没有工作目录本身。

  • 另一种解决方案是针对您推送的存储库,使两个工作目录,可以使用contrib/workdir中的git-new-workdir脚本创建。这些工作区域中的每一个都将是该存储库的适当分支的结帐。

    然后updatepost-receive挂钩会取消设置GIT_DIR,转到这些工作区域(public_htmlbeta_public_html),并执行“{{1} “那里。

    在此解决方案中,“checkouts”会在其中包含一些与git相关的元信息(在隐藏的git reset --hard目录中)。

  • 另一种解决方案是拥有两个(附加)从属存储库。然后推入主(主)存储库(通过挂钩)或者推入这两个从属存储库,其钩子将执行“.git”或等效,或者转到这两个从属存储库并执行“{{1 “来自那里的主人。

    这两个奴隶库将是非裸的,可以[直接在] git reset --hardgit pull。在这个解决方案中,“checkouts”将是完整的git存储库本身。

    您可以通过让这些从属存储库具有“替代”(备用对象数据库)以指向主存储库(即使用“public_html”克隆)来改进此设置;如果没有这个对象,奴隶中的数据库就开始硬连接到master。当然,只有当主设备和从设备位于同一文件系统上时,才可能这样做。

    请注意,此解决方案允许主存​​储库位于与从属存储库不同的主机上。 (虽然我猜这是你不需要的灵活性)。

  • 最后,你可以代替当前的设置部署gitweb或其他一些 git web界面(参见InterfacesFrontendsAndToolsGitweb wiki页面获取部分列表),所以您的用户可以在闲暇时浏览存储库的不同版本和不同分支。

    在gitweb中(我猜也在其他git web界面中)由于path_info URL支持,您可以在浏览器中查看文件,并正确地跟踪链接(如果它们是本地的),请参阅例如git.html from 'html' branch of git.git repository at repo.or.cz


P.S。默认情况下,“beta_public_html”不会更新远程存储库中的工作目录,因为如果有人在非裸存储库中工作,那么这种横向推送可能会非常意外并导致失去工作。

答案 2 :(得分:0)

我使用这样的post-receive hook来发布我的网站,因为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

  

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

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

答案 3 :(得分:0)

我并不是真的反对其他解决方案,但我认为这样做的“黑方”“Git方式”更少。这就是我要做的事情:

  1. 在我的服务器上,我设置了一种集中式存储库(由Gitosis或其他类似的东西管理)。
  2. 从客户端,我不断从存储库中取出,进行更改并推回。分支机构是自动管理的。
  3. 我将Gitosis所需的分支拉到服务器的public_html / beta_public_html。我会定期使用Cron作业与Gitosis保持同步。如果您不喜欢Cron工作的想法,您可以随时使用某种钩子+脚本,就像其他人指出的那样。