在 Capistrano 中部署 Git 子目录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29168/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deploying a Git subdirectory in Capistrano
提问by Jarin Udom
My master branch layout is like this:
我的主分支布局是这样的:
/<-- top level
/<-- 顶级
/client<-- desktop client source files
/client<-- 桌面客户端源文件
/server<-- Rails app
/server<-- Rails 应用程序
What I'd like to do is only pull down the /server directory in my deploy.rb, but I can't seem to find any way to do that. The /client directory is huge, so setting up a hook to copy /server to / won't work very well, it needs to only pull down the Rails app.
我想要做的只是拉下我的 /server 目录deploy.rb,但我似乎找不到任何方法来做到这一点。/client 目录很大,所以设置一个钩子将 /server 复制到 / 不会很好地工作,它只需要拉下 Rails 应用程序。
回答by thodg
Without any dirty forking action but even dirtier !
没有任何肮脏的分叉动作,但更脏!
In my config/deploy.rb :
在我的 config/deploy.rb 中:
set :deploy_subdir, "project/subdir"
Then I added this new strategy to my Capfile :
然后我将这个新策略添加到我的 Capfile 中:
require 'capistrano/recipes/deploy/strategy/remote_cache'
class RemoteCacheSubdir < Capistrano::Deploy::Strategy::RemoteCache
private
def repository_cache_subdir
if configuration[:deploy_subdir] then
File.join(repository_cache, configuration[:deploy_subdir])
else
repository_cache
end
end
def copy_repository_cache
logger.trace "copying the cached version to #{configuration[:release_path]}"
if copy_exclude.empty?
run "cp -RPp #{repository_cache_subdir} #{configuration[:release_path]} && #{mark}"
else
exclusions = copy_exclude.map { |e| "--exclude=\"#{e}\"" }.join(' ')
run "rsync -lrpt #{exclusions} #{repository_cache_subdir}/* #{configuration[:release_path]} && #{mark}"
end
end
end
set :strategy, RemoteCacheSubdir.new(self)
回答by Mr Friendly
For Capistrano 3.0, I use the following:
对于 Capistrano 3.0,我使用以下内容:
In my Capfile:
在我的Capfile:
# Define a new SCM strategy, so we can deploy only a subdirectory of our repo.
module RemoteCacheWithProjectRootStrategy
def test
test! " [ -f #{repo_path}/HEAD ] "
end
def check
test! :git, :'ls-remote', repo_url
end
def clone
git :clone, '--mirror', repo_url, repo_path
end
def update
git :remote, :update
end
def release
git :archive, fetch(:branch), fetch(:project_root), '| tar -x -C', release_path, "--strip=#{fetch(:project_root).count('/')+1}"
end
end
And in my deploy.rb:
而在我的deploy.rb:
# Set up a strategy to deploy only a project directory (not the whole repo)
set :git_strategy, RemoteCacheWithProjectRootStrategy
set :project_root, 'relative/path/from/your/repo'
All the important code is in the strategy releasemethod, which uses git archiveto archive only a subdirectory of the repo, then uses the --stripargument to tarto extract the archive at the right level.
所有重要的代码都在 strategyrelease方法中,该方法git archive仅用于存档 repo 的子目录,然后使用--strip参数 totar在正确的级别提取存档。
UPDATE
更新
As of Capistrano 3.3.3, you can now use the :repo_treeconfiguration variable, which makes this answer obsolete. For example:
从 Capistrano 3.3.3 开始,您现在可以使用:repo_tree配置变量,这使得此答案已过时。例如:
set :repo_url, 'https://example.com/your_repo.git'
set :repo_tree, 'relative/path/from/your/repo' # relative path to project root in repo
See http://capistranorb.com/documentation/getting-started/configuration.
请参阅http://capistranorb.com/documentation/getting-started/configuration。
回答by Thomas Fankhauser
We're also doing this with Capistrano by cloning down the full repository, deleting the unused files and folders and move the desired folder up the hierarchy.
我们还在 Capistrano 中通过克隆完整存储库、删除未使用的文件和文件夹并将所需的文件夹向上移动到层次结构来执行此操作。
deploy.rb
部署文件
set :repository, "[email protected]:name/project.git"
set :branch, "master"
set :subdir, "server"
after "deploy:update_code", "deploy:checkout_subdir"
namespace :deploy do
desc "Checkout subdirectory and delete all the other stuff"
task :checkout_subdir do
run "mv #{current_release}/#{subdir}/ /tmp && rm -rf #{current_release}/* && mv /tmp/#{subdir}/* #{current_release}"
end
end
As long as the project doesn't get too big this works pretty good for us, but if you can, create an own repository for each component and group them together with git submodules.
只要项目不会变得太大,这对我们来说就很好,但是如果可以的话,为每个组件创建一个自己的存储库,并将它们与 git 子模块组合在一起。
回答by Federico Builes
You can have two git repositories (client and server) and add them to a "super-project" (app). In this "super-project" you can add the two repositories as submodules (check this tutorial).
您可以拥有两个 git 存储库(客户端和服务器)并将它们添加到“超级项目”(应用程序)。在这个“超级项目”中,您可以将两个存储库添加为子模块(查看本教程)。
Another possible solution (a bit more dirty) is to have separate branches for client and server, and then you can pull from the 'server' branch.
另一种可能的解决方案(有点脏)是为客户端和服务器设置单独的分支,然后您可以从“服务器”分支中提取。
回答by Simon Woodside
There is a solution. Grab crdlo's patch for capistranoand the capistrano sourcefrom github. Remove your existing capistrano gem, appy the patch, setup.rb install, and then you can use his very simple configuration line set :project, "mysubdirectory"to set a subdirectory.
有一个解决方案。从 github获取crdlo 的capistrano 补丁和capistrano 源。删除您现有的 capistrano gem,应用补丁,安装 setup.rb,然后您可以使用他非常简单的配置行set :project, "mysubdirectory"来设置子目录。
The only gotcha is that apparently github doesn't "support the archive command" ... at least when he wrote it. I'm using my own private git repo over svn and it works fine, I haven't tried it with github but I imagine if enough people complain they'll add that feature.
唯一的问题是显然 github 不“支持存档命令”……至少在他编写它的时候是这样。我在 svn 上使用我自己的私有 git repo 并且它工作正常,我还没有在 github 上尝试过,但我想如果有足够多的人抱怨他们会添加该功能。
Also see if you can get capistrano authors to add this feature into cap at the relevant bug.
回答by fsainz
For Capistrano 3, based on @Thomas Fankhauser answer:
对于 Capistrano 3,基于@Thomas Fankhauser 的回答:
set :repository, "[email protected]:name/project.git"
set :branch, "master"
set :subdir, "relative_path_to_my/subdir"
namespace :deploy do
desc "Checkout subdirectory and delete all the other stuff"
task :checkout_subdir do
subdir = fetch(:subdir)
subdir_last_folder = File.basename(subdir)
release_subdir_path = File.join(release_path, subdir)
tmp_base_folder = File.join("/tmp", "capistrano_subdir_hack")
tmp_destination = File.join(tmp_base_folder, subdir_last_folder)
cmd = []
# Settings for my-zsh
# cmd << "unsetopt nomatch && setopt rmstarsilent"
# create temporary folder
cmd << "mkdir -p #{tmp_base_folder}"
# delete previous temporary files
cmd << "rm -rf #{tmp_base_folder}/*"
# move subdir contents to tmp
cmd << "mv #{release_subdir_path}/ #{tmp_destination}"
# delete contents inside release
cmd << "rm -rf #{release_path}/*"
# move subdir contents to release
cmd << "mv #{tmp_destination}/* #{release_path}"
cmd = cmd.join(" && ")
on roles(:app) do
within release_path do
execute cmd
end
end
end
end
after "deploy:updating", "deploy:checkout_subdir"
回答by Silas Snider
Unfortunately, git provides no way to do this. Instead, the 'git way' is to have two repositories -- client and server, and clone the one(s) you need.
不幸的是,git 没有提供这样做的方法。相反,“git 方式”是拥有两个存储库——客户端和服务器,并克隆您需要的一个。
回答by JAlberto
I created a snipped that works with Capistrano 3.x based in previous anwers and other information found in github:
我根据以前的答案和在 github 中找到的其他信息创建了一个与 Capistrano 3.x 一起使用的片段:
# Usage:
# 1. Drop this file into lib/capistrano/remote_cache_with_project_root_strategy.rb
# 2. Add the following to your Capfile:
# require 'capistrano/git'
# require './lib/capistrano/remote_cache_with_project_root_strategy'
# 3. Add the following to your config/deploy.rb
# set :git_strategy, RemoteCacheWithProjectRootStrategy
# set :project_root, 'subdir/path'
# Define a new SCM strategy, so we can deploy only a subdirectory of our repo.
module RemoteCacheWithProjectRootStrategy
include Capistrano::Git::DefaultStrategy
def test
test! " [ -f #{repo_path}/HEAD ] "
end
def check
test! :git, :'ls-remote -h', repo_url
end
def clone
git :clone, '--mirror', repo_url, repo_path
end
def update
git :remote, :update
end
def release
git :archive, fetch(:branch), fetch(:project_root), '| tar -x -C', release_path, "--strip=#{fetch(:project_root).count('/')+1}"
end
end
It's also available as a Gist on Github.
它也可以作为Github上的 Gist 使用。
回答by Stephan Wehner
This has been working for me for a few hours.
这已经对我来说有效了几个小时。
# Capistrano assumes that the repository root is Rails.root
namespace :uploads do
# We have the Rails application in a subdirectory rails_app
# Capistrano doesn't provide an elegant way to deal with that
# for the git case. (For subversion it is straightforward.)
task :mv_rails_app_dir, :roles => :app do
run "mv #{release_path}/rails_app/* #{release_path}/ "
end
end
before 'deploy:finalize_update', 'uploads:mv_rails_app_dir'
You might declare a variable for the directory (here rails_app).
您可以为目录声明一个变量(此处为 rails_app)。
Let's see how robust it is. Using "before" is pretty weak.
让我们看看它有多健壮。使用“before”是很弱的。
回答by StuFF mc
Looks like it's also not working with codebasehq.com so I ended up making capistrano tasks that cleans the mess :-) Maybe there's actually a less hacky way of doing this by overriding some capistrano tasks...
看起来它也不适用于 codebasehq.com 所以我最终制作了清理混乱的 capistrano 任务:-) 也许通过覆盖一些 capistrano 任务实际上有一种不那么黑客的方法......

