Git远程裸仓库上的子模块

26

我已经设置好了环境,可以将代码推送到远程裸仓库。 我使用以下命令来设置远程仓库:

$ mkdir ~/website.git && cd ~/website.git
$ git init --bare

并且

$ cat > hooks/post-receive

#!/bin/sh
GIT_WORK_TREE=/var/www/website git checkout -f

$ chmod +x hooks/post-receive

而在我的本地环境上:

$ git remote add web ssh://website.com/home/website.git
$ git push web +master:refs/heads/master

现在我可以使用git push web将代码部署到远程,一切都很顺利。

问题:子模块

我的项目中有一些子模块,它们没有被初始化/更新到远程仓库。由于这是裸库,因此我无法在其上运行git submodule update命令;而在/var/www/website文件夹上运行也不行,因为它只是文件的副本,而不是 Git 仓库。

3个回答

14

我找到了另一种解决方案,它看起来相当清晰。只需向 Git 提供执行子模块操作所需的所有信息:

$ cd /path/to/your/git_work_tree
$ git --git-dir=/path/to/your/bare_repo.git --work-tree=. submodule init
$ git --git-dir=/path/to/your/bare_repo.git --work-tree=. submodule update

你如何自动化这个过程,以便在每次“push”部署后都能执行它? - Xtremefaith

11

可能的一种方式是:

换句话说:
从裸库中拉取而非尝试从裸库中检出代码:这样,非裸库就可以容纳git submodule update 步骤。

一个示例脚本可能是这样的:

#!/bin/sh

# Get the latest code
cd /path/to/bare/repo

# Set git variables
GIT_WORK_TREE=/var/www/website
GIT_DIR=/var/www/website/.git

# Go to website and pull
cd /var/www/website
git pull /path/to/bare/repo
git submodule update --init --recursive

# Run additional build stuff here

你能提供一个post-receive/post-update脚本的例子吗(虽然这个答案很旧)?我每次尝试推送都会出现错误。 - akohout
@raveN,在/var/www/website目录下是否有.git文件夹? - VonC
1
GIT_DIR被设置为/var/ww/website/.gitGIT_WORK_TREE被设置为/var/ww/website/了吗? - VonC
啊,GIT_DIR 没有设置为 .git - 非常感谢你的快速帮助。我将编辑您的答案以提供一个完整的示例。 - akohout
1
@johnshumon 对的!我已经删除了不必要的步骤。不确定6年前我在想什么,当时写下这个答案... - VonC
显示剩余3条评论

6
我两天前偶然看到了这个主题,当时我也在苦苦挣扎。最终找到了一个简洁明了的解决方案,并在这里写了一篇文章:

Git push with submodules: a how-to guide

我意识到,如果我要向裸仓库(push)发送请求,只是为了使用post-receive来从非裸仓库(pull)中提取信息,那么我不妨简单地直接向非裸仓库推送(push)。 在这种情况下,“最佳实践”只会增加复杂性。 如遇链接失效,请查看以下解决方案,省略我遇到与您相同的所有问题的部分。
首先,让我们创建一个“通用”的post-receive钩子(universal post-receive hook),一个无需按每个存储库更改的钩子。
[aaron@aaronadams]$ cat > /usr/local/share/git-core/templates/hooks/post-receive.sample
#!/bin/sh
#
# An example hook script to update the working tree, including its
# submodules, after receiving a push.
#
# This hook requires core.worktree to be explicitly set, and
# receive.denyCurrentBranch to be set to false.
#
# To enable this hook, rename this file to "post-receive".

# Read standard input or hook will fail
while read oldrev newrev refname
do
:
done

# Unset GIT_DIR or the universe will implode
unset GIT_DIR

# Change directory to the working tree; exit on failure
cd `git config --get core.worktree` || exit

# Force checkout
git checkout --force

# Force update submodules
git submodule update --init --recursive --force
[aaron@aaronadams]$ chmod +x /usr/local/share/git-core/templates/hooks/post-receive.sample

现在让我们打破所有规则。我们将在网站目录中初始化一个非裸的Git仓库;确保它可以从git push接收;明确将其工作树设置为其父目录;并启用我们刚创建的钩子。
[aaron@aaronadams]$ cd /var/www/vhosts/aaronadams.ca/sites/staging.aaronadams.ca
[aaron@aaronadams]$ git init && git config --bool receive.denyCurrentBranch false && git config --path core.worktree ../ && mv .git/hooks/post-receive.sample .git/hooks/post-receive
Initialized empty Git repository in /var/www/vhosts/aaronadams.ca/sites/staging.aaronadams.ca/.git/

最后,在我们的本地机器上,我们将更改远程仓库以反映我们新仓库的位置,并推送。

[aaron@aaronadams]$ git remote set-url staging aaron@aaronadams.ca:sites/staging.aaronadams.ca
[aaron@aaronadams]$ git push staging master
remote: Submodule 'codeigniter' (git://github.com/EllisLab/CodeIgniter.git) registered for path 'codeigniter'
remote: Cloning into 'codeigniter'...
remote: Submodule path 'codeigniter': checked out 'fd24adf31255822d6aa9a5d2dce9010ad2ee4cf0'
To aaron@aaronadams.ca:sites/staging.aaronadams.ca
 * [new branch]      master -> master

天啊,它行了!

这种方法不仅能兼容子模块,还只需要一个命令来设置新的远程仓库(好吧,由四个命令组成)。它还将仓库和工作树放在同一个位置;并且我们的配置或挂钩文件中不需要绝对路径,现在也是完全可移植的。


我希望这个答案能像其他人的 Stack Exchange 帖子一样,在过去的两天里帮助某些人!


我尝试了你的文章,但在第一次推送之后就出现了错误。我注意到它没有将文件存储在objects目录中。错误是:error: unable to create temporary sha1 filename ./objects/9e: No such file or directory。我认为它应该是.git/objects/9e。有什么想法吗?这非常接近。 - Dobler
1
如果多个程序员部署到同一个网站,这可能会导致问题。请参阅“全面了解裸仓库”。VonC的解决方案避免了这个问题。 - jrhorn424
2
@jrhorn424 确实,上述解决方案存在很多问题;自从我编写它以来,我已经学到了很多东西,其中最重要的是子模块会带来更多问题而不是解决问题。我强烈建议切换到我在这里记录的无子模块解决方案:https://dev59.com/bG3Xa4cB1Zd3GeqPkvmz - Aaron Adams
谢谢,@AaronAdams。写得很好。实际上,我最终无法让VonC的解决方案起作用,而这种“伪裸”技术实际上是由vcsh使用的。由于我的用例是点文件,所以我认为这是可以的,但我不会将其用于网站。 - jrhorn424
1
@jrhorn424,我的原始博客文章记录了我在尝试自己实现该解决方案时遇到的所有困难。 - Aaron Adams
显示剩余3条评论

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