【发布时间】:2017-06-22 02:24:03
【问题描述】:
我正在使用 Jekyll 构建站点,它编译 ERB、SASS 等。转换成纯 HTML 和 CSS。
在大多数提交之后,我想编译站点并将编译后的版本提交到单独的存储库或分支中,以便可以将其推送到静态服务器。
最好的方法是什么?
我已经有a solution,但我希望有人可能有一个更优雅的。
【问题讨论】:
标签: git githooks post-commit-hook
我正在使用 Jekyll 构建站点,它编译 ERB、SASS 等。转换成纯 HTML 和 CSS。
在大多数提交之后,我想编译站点并将编译后的版本提交到单独的存储库或分支中,以便可以将其推送到静态服务器。
最好的方法是什么?
我已经有a solution,但我希望有人可能有一个更优雅的。
【问题讨论】:
标签: git githooks post-commit-hook
在大多数提交之后,我想编译站点并将编译后的版本提交到单独的存储库或分支中,以便可以将其推送到静态服务器。
适合您的关键字是“持续集成”。
您可以在每次提交后、创建或修改拉取请求后或仅在夜间使用 Jenkins 等 CI 软件构建系统。
您在 CI 软件中配置的构建脚本负责将构建工件(在这种情况下为您的编译版本)部署到您的目标系统,例如 s3 存储桶。您还可以将您的人工制品以编程方式提交到不同的 git 存储库。
【讨论】:
您的解决方案将在同一个存储库中混合“源提交”和“交付提交”(_site 编译版本),这不是最佳实践(并且会不必要地增加 Git 存储库的大小)
我将创建一个单独的存储库“site”,并将其作为 submodule 添加到您当前的存储库中,路径名为 _site/。
cd /path/to/current/repo
git rm -R _site
git submodule add -- /url/repo/site _site
这样,每次使用 bundle exec jekyll build 构建交付时,它都在一个单独的 repo(_site)中完成,您可以在其中添加、提交,甚至直接推送到您想要测试的地方.
然后你回到你的主仓库,在那里你添加并提交 gitlink (special entry in the index),在源代码的确切版本和交付的确切版本之间建立了牢固的联系(建成的网站)。
【讨论】:
git init _site/,所以提交实际上是转到一个单独的存储库。在我看来,如果有的话,source 应该是子模块。
git init 不会使其成为子模块,只会成为嵌套的 git 存储库,这很糟糕,正如我在 stackoverflow.com/a/41968295/6309 中详述的那样。
.gitignore 中有_site/,有什么办法可以用这个设置让我自己一枪毙命吗?
如您所愿
我不建议您使用相同的存储库来存储已编译的代码。因为它可以从任何状态的源代码中获取,并且会不必要地重复信息。
所以,在这种情况下,您想使用 git 作为 CI 工具。您应该为已编译的站点创建另一个 repo,并在每次需要时提交。
我建议您为代码的“生产”状态选择分支。当您在该分支中提交时 - 应该重建代码。让我们将其命名为“生产”。
srcDir='../srcWorkTree'
buildedRepo='../buildedRepo'
if [ `git rev-parse --abbrev-ref HEAD` == "production" ]; then
echo "making builded code commit..."
mkdir -p $srcDir
# http://stackoverflow.com/questions/4479960/git-checkout-to-a-specific-folder
git checkout-index -a -f --prefix=$srcDir/
bundle exec jekyll build --source $srcDir --destination $buildedRepo
cd $buildedRepo
git add -A
commitInfo=$( git log -1 --pretty="%h %B" )
git commit -m "autobuild for $commitInfo"
# git push
fi
另一种变体
我可以假设,您可以访问您的生产服务器。至少你提到你在那里有 git repo。因此,在接收后挂钩将您的代码构建到目标目录中是合理的。它会更清晰和简单,而不是像我描述的那样在本地机器上进行。
我认为这个 repo 是“裸露的”,因为您不应该在服务器上进行更改。
接收后挂钩:
#!/bin/sh
siteDir='/var/www/site'
tmpSrcDir='/var/www/site'
echo "**** [builder's post-receive hook]"
while read oldrev newrev refname
do
if [ $refname = refs/heads/production ]
then
GIT_WORK_TREE=$tmpSrcDir git checkout --detach $newrev
bundle exec jekyll build --source $tmpSrcDir --destination $siteDir
fi
done
exit 0
还有几个cmets
我明白了,您尝试使用子模块来存储您构建的站点。我不建议这样做。没有意义,因为您的源代码不依赖于构建的代码。
【讨论】:
我只是建议另一种选择:不要将编译后的版本存储在 git 中,将它们存储在其他地方。
以我们的工作流程为例:
当我们需要测试特定的提交时,我们通过生成 .tar.gz 存档的 CI 进程运行它,并使用我们的部署工具在暂存服务器上对其进行测试;
当我们选择一个发布版本的提交时,我们在 git 中标记这个提交,我们通过整个 CI 过程运行它,.tar.gz 标有版本号并存储在某个 releases/ 目录中在我们的部署服务器上。
我们有一个 releases/ 文件夹的备份,但如果我们丢失它,我们也可以从源代码重建任何特定的构建(基于标签)。
【讨论】:
在_site/中初始化一个Git repo,然后添加一个Git post-commit hook,.git/hooks/post-commit:
echo -n "Add commit to compiled version? (y/N) "
read answer < /dev/tty
if [ "$answer" != "y" ]; then exit; fi
message=$( git log -1 --pretty=%B )
git stash --all
bundle exec jekyll build
cd _site
git add --all
git commit -m "$message"
cd ..
git stash pop
现在,每次提交时,系统都会询问您是否要向已编译的版本添加提交。
【讨论】: