在制作中,我维护了两个网站 - 测试和发布。每个都通过软链接指向不同的目录(例如)
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是两个步骤。)
感谢。我想回到编写代码。
答案 0 :(得分:3)
文章Git push is worse than worsless对类似问题进行了有趣的讨论。
其解决方案和结论之一涉及:
所以在你的情况下,
简而言之:一步: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)
解决方案是推送到单个存储库,该存储库将使用update
或post-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脚本创建。这些工作区域中的每一个都将是该存储库的适当分支的结帐。
然后update
或post-receive
挂钩会取消设置GIT_DIR
,转到这些工作区域(public_html
和beta_public_html
),并执行“{{1} “那里。
在此解决方案中,“checkouts”会在其中包含一些与git相关的元信息(在隐藏的git reset --hard
目录中)。
另一种解决方案是拥有两个(附加)从属存储库。然后推入主(主)存储库(通过挂钩)或者推入这两个从属存储库,其钩子将执行“.git
”或等效,或者转到这两个从属存储库并执行“{{1 “来自那里的主人。
这两个奴隶库将是非裸的,可以[直接在] git reset --hard
和git pull
。在这个解决方案中,“checkouts”将是完整的git存储库本身。
您可以通过让这些从属存储库具有“替代”(备用对象数据库)以指向主存储库(即使用“public_html
”克隆)来改进此设置;如果没有这个对象,奴隶中的数据库就开始硬连接到master。当然,只有当主设备和从设备位于同一文件系统上时,才可能这样做。
请注意,此解决方案允许主存储库位于与从属存储库不同的主机上。 (虽然我猜这是你不需要的灵活性)。
最后,你可以代替当前的设置部署gitweb或其他一些 git web界面(参见InterfacesFrontendsAndTools和Gitweb 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方式”更少。这就是我要做的事情: