在Capistrano中部署Git子目录


67

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

/ <-顶层

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

/ server <-Rails应用

我想做的只是在我的目录中拉/ server目录deploy.rb,但是我似乎找不到任何方法。/ client目录很大,因此设置一个将/ server复制到/的钩子将无法很好地工作,它只需要拉下Rails应用程序即可。

Answers:


78

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

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

14
哦,我希望我能给你几品脱的库尔德啤酒。谢谢!!
纳扎尔

3
完善。正是我所需要的。谢谢!
马特

注意 任何人阅读,这样的作品,如果你已经使用remote_cache为您:deploy_via机制(其依靠在服务器端SCM访问。)
JRG

看起来不错!有没有人把它烤成宝石?
M. Scott Ford


43

对于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'

所有重要的代码都在strategyrelease方法中,该方法git archive仅用于存档存储库的子目录,然后使用--strip参数tar在正确的级别提取存档。

更新

从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

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


我无法使用'set:git_strategy'设置自定义策略,它一直使用DefaultStrategy
leojh 2014年

7
我还需要从原来的复制和粘贴“fetch_revision”方法(github.com/capistrano/capistrano/blob/master/lib/capistrano/...
恒雄吉冈

1
@TsuneoYoshioka是的,Capistrano 3.1中添加了“ fetch_revision”方法。但是,3.1还添加了“ repo_tree”配置变量,(很高兴)使此答案过时了。有关详细信息,请参见github.com/capistrano/capistrano#configuration
友谊先生2014年

4
:repo_tree实际上是在3.3.3中而非3.1中添加的。对于那些看到这一点,但对他们不起作用的人。
同名

嗨,我使用的是capistrano 3.4.0,但仍然不能使用:repo_tree变量来使其工作。我有一个名为demo_app的git repo ,它有两个子目录serverclient。我想使用服务器子目录进行部署。如何使用:repo_tree进行设置?这些都set :repo_tree, 'demo_app/server' set :repo_tree, 'server'
不起作用

10

我们还通过关闭整个存储库,删除未使用的文件和文件夹,并将所需的文件夹移到层次结构中,来使用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

只要项目规模不大,这对我们来说就很好了,但如果可以的话,请为每个组件创建一个自己的存储库,并将它们与git子模块组合在一起。


1
真好!效率低下,但至少不是丑陋的骇客。
Michiel de Mare

并且不要忘记手动符号链接日志目录,因为capistrano不再自动执行此操作
。–

2
为更有效的方法。有人创建了一个gem,添加了部署策略“ copy_subdir”。仅仓库中的子目录被存档并复制到远程服务器。 github.com/yyuu/capistrano-copy-subdir
凯文(Kevin)

知道我们该如何基于角色吗?
萨拉特2014年

3

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

另一个可能的解决方案(更加肮脏)是为客户端和服务器分别设置分支,然后您可以从“服务器”分支中拉出。


2

有一个解决方案。抓取针对capistrano的crdlo补丁和来自github的capistrano源代码。删除您现有的capistrano gem,应用补丁,安装setup.rb,然后您可以使用他的非常简单的配置行set :project, "mysubdirectory"来设置子目录。

唯一的问题是,显然github至少在写时不“支持archive命令”。我在svn上使用了自己的私有git repo,它工作正常,我还没有在github上尝试过,但是我想如果有足够多的人抱怨他们会添加该功能。

另请查看是否可以让capistrano作者在相关的bug处将此功能添加到cap


灯塔链接断开。我想知道capistrano是否同时实施了此功能。
米歇尔·德马雷

2

对于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"

1

不幸的是,git无法做到这一点。相反,“ git方法”是拥有两个存储库-客户端和服务器,并克隆所需的存储库。


提到“ git方式”并没有任何帮助。
Sjors Branderhorst

1

我创建了一个片段,该片段与Capistrano 3.x一起使用,基于以前的答案以及在github中找到的其他信息:

# 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使用。


意外地一直向下滚动并找到了它。为我工作,+ 1。
Jorge Orpinel,2015年

它也对我也很好...谢谢+1我现在可以部署api版本v1,v2……

0

看起来它也无法与codebasehq.com一起使用,所以我最终完成了清理混乱的capistrano任务:-)也许实际上,通过重写一些capistrano任务,这种方法不太麻烦。


0

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

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

您可以为目录声明一个变量(此处为rails_app)。

让我们看看它有多健壮。使用“之前”是相当弱的。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.