在Capistrano中部署一个Git子目录

我的主分支布局是这样的:

/ < – 顶层

/ client < – 桌面客户端源文件

/ server < – Rails应用程序

我想要做的只是拉下我的deploy.rb的/ server目录,但我似乎无法find任何方法来做到这一点。 / client目录是巨大的,所以设置一个钩子来复制/服务器到/不会工作得很好,它只需要拉下Rails应用程序。

没有任何肮脏的分叉动作,但更脏!

在我的config / deploy.rb中:

 set :deploy_subdir, "project/subdir" 

然后我把这个新的策略添加到我的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) 

对于Capistrano 3.0,我使用以下内容:

在我的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 

在我的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' 

所有重要的代码都在策略release方法中,它使用git archive来仅存档回购的子目录,然后使用tar参数--strip来提取正确级别的存档。

UPDATE

从Capistrano 3.3.3开始,现在可以使用:repo_treeconfigurationvariables,这使得这个答案已经过时了。 例如:

 set :repo_url, 'https://example.com/your_repo.git' set :repo_tree, 'relative/path/from/your/repo' # relative path to project root in repo 

请参阅http://capistranorb.com/documentation/getting-started/configuration

我们还通过克隆完整的存储库,删除未使用的文件和文件夹,并将所需的文件夹移到层次结构中来完成Capistrano的操作。

deploy.rb

 set :repository, "git@github.com: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 

只要项目不会太大,这对我们来说是相当不错的,但是如果可以的话,可以为每个组件创build一个自己的仓库,并使用git子模块将它们组合在一起。

你可以有两个git仓库(客户端和服务器),并将其添加到“超级项目”(应用程序)。 在这个“超级项目”中,您可以将这两个存储库添加为子模块(请查看本教程 )。

另一个可能的解决scheme(更肮脏)是为客户端和服务器分开的分支,然后你可以从“服务器”分支拉。

不幸的是,git没有办法做到这一点。 相反,'git的方式'是有两个存储库 – 客户端和服务器,并克隆你需要的一个或多个。

有一个解决scheme。 抓住crdlo的capistrano补丁和github的capistrano源码 。 删除你现有的capistrano gem,appy补丁,setup.rb install,然后你可以使用他非常简单的configuration行set :project, "mysubdirectory"来设置一个子目录。

唯一的问题是Github显然不支持归档命令……至less在他写这个命令的时候。 我使用我自己的私人git回购svn,它工作正常,我没有尝试与github,但我想如果足够的人抱怨他们会添加该function。

另外看看你是否可以让capistrano的作者把这个特性添加到相关的bug中 。

对于Capistrano 3,基于@Thomas Fankhauser的回答:

 set :repository, "git@github.com: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" 

看起来它也没有与codebasehq.com工作,所以我最终使capistrano任务,清理混乱:-)也许实际上是一个更less的hacky通过重写一些capistrano任务的方式…

我创build了一个基于以前的awers和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 

它也可以在Github上作为Gist使用。

这已经为我工作了几个小时。

 # 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' 

你可以为目录声明一个variables(这里是rails_app)。

让我们看看它是多么强大。 使用“之前”是相当薄弱的。

Interesting Posts