在 Capistrano 中部署 Git 子目录

Deploying a Git subdirectory in Capistrano

提问人:Jarin Udom 提问时间:8/27/2008 最后编辑:Charles MenguyJarin Udom 更新时间:10/17/2023 访问量:15540

问:

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

/<--顶级

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

/server <-- Rails 应用程序

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

Ruby-on-Rails Git 部署 Capistrano

评论


答:

1赞 Silas Snider 8/27/2008 #1

不幸的是,git 没有提供做到这一点的方法。取而代之的是,“git 方式”是拥有两个存储库——客户端和服务器,并克隆您需要的存储库。

评论

0赞 Sjors Branderhorst 1/28/2016
提及“git 方式”对任何事情或任何人都没有帮助。
3赞 Federico Builes 8/30/2008 #2

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

另一种可能的解决方案(更脏一点)是为客户端和服务器设置单独的分支,然后您可以从“服务器”分支中提取。

2赞 Simon Woodside 5/14/2009 #3

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

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

还要看看你是否可以让 capistrano 作者在相关 bug 处将此功能添加到上限中。

评论

0赞 Michiel de Mare 7/1/2012
Lighthouse 链接已断开。我想知道 capistrano 是否在此期间实现了这一点。
0赞 StuFF mc 9/17/2009 #4

看起来它也不适用于 codebasehq.com 所以我最终制作了清理混乱的 capistrano 任务:-)也许实际上有一种不那么笨拙的方法,通过覆盖一些 capistrano 任务来做到这一点......

79赞 thodg 1/12/2010 #5

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

在我的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赞 Nazar 7/12/2011
哦,我多么希望我能送你几品脱咕噜咕噜的啤酒。谢谢!!
0赞 jrg 5/30/2013
铌。任何阅读的人,如果您已经在使用 remote_cache 作为 :d eploy_via 机制(它依赖于服务器端的 SCM 访问),这就会起作用。
0赞 M. Scott Ford 7/31/2013
这看起来不错!有没有人把它烤成宝石?
1赞 M. Scott Ford 7/31/2013
这看起来可能有潜力......github.com/mcollina/capistrano-remote-cache-with-project-root
1赞 i_use_the_internet 3/7/2018
我不断收到加载错误:未找到“capistrano/recipes/deploy/strategy/remote_cache”文件。我正在使用 Capistrano 3
0赞 Stephan Wehner 8/7/2011 #6

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

# 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)。

让我们看看它有多强大。使用“before”是相当弱的。

10赞 Thomas Fankhauser 1/19/2012 #7

我们还通过克隆完整的存储库,删除未使用的文件和文件夹,并将所需的文件夹向上移动到层次结构中来做到这一点。

部署.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

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

评论

1赞 Michiel de Mare 7/1/2012
好!效率有点低,但至少不是一个丑陋的黑客。
0赞 Thomas Fankhauser 7/2/2012
并且不要忘记手动符号链接日志目录,因为 capistrano 不再自动执行此操作。
2赞 Kevin 5/17/2013
为了更有效的方法。有人创建了一个 gem,它添加了部署策略“copy_subdir”。只有存储库中的子目录被存档并复制到远程服务器。github.com/yyuu/capistrano-copy-subdir
0赞 sarat 10/12/2014
知道我们如何基于这个角色吗?
44赞 Mr Friendly 1/25/2014 #8

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

所有重要的代码都在 strategy 方法中,该方法仅用于存档 repo 的子目录,然后使用参数在正确的级别提取存档。releasegit archive--striptar

更新

从 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

评论

0赞 leojh 2/18/2014
我无法使用“set :git_strategy”设置自定义策略,它一直使用 DefaultStrategy
7赞 Tsuneo Yoshioka 5/1/2014
我还需要从原始方法中复制和粘贴“fetch_revision”方法。(github.com/capistrano/capistrano/blob/master/lib/capistrano/......)
1赞 Mr Friendly 12/18/2014
@TsuneoYoshioka 是的,“fetch_revision”方法已添加到 Capistrano 3.1 中。但是,3.1 还添加了“repo_tree”配置变量,这(令人高兴地)使这个答案过时了。有关详细信息,请参见 github.com/capistrano/capistrano#configuration
4赞 Altonymous 3/4/2015
:repo_tree 实际上是在 3.3.3 而不是 3.1 中添加的。对于那些看到这一点并且对他们不起作用的人。
0赞 chetang 7/1/2015
嗨,我正在使用 capistrano 3.4.0,但我仍然无法使用 :repo_tree 变量来使其工作。我有一个名为 demo_app 的 git 存储库,它有两个子目录服务器客户端。我想使用服务器子目录进行部署。如何使用 :repo_tree 进行设置?这些都不起作用:- 或set :repo_tree, 'demo_app/server' set :repo_tree, 'server'
1赞 JAlberto 5/6/2014 #9

我创建了一个与 Capistrano 3.x 一起使用的截图,该剪裁基于以前的 anwers 和 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

它也可以作为 Gist 在 Github 上提供。

评论

0赞 Jorge Orpinel Pérez 8/6/2015
不小心一直向下滚动,发现了这个。对我有用,+1。
0赞 2/29/2016
它对我来说也很好用......谢谢 +1 我现在可以部署 api 版本 v1、v2 、...
2赞 fsainz 8/22/2014 #10

对于 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"
1赞 fFace 2/8/2020 #11

不知道有没有人还对此感兴趣。但如果有人正在寻找答案,就让你们。 现在我们可以使用:repo_tree

https://capistranorb.com/documentation/getting-started/configuration/

2赞 edimossilva 10/17/2023 #12

在 capistrano 3.17.3 中,下面的解决方案对我有用,它的灵感来自于Thomas Fankhauser

  • use 代替release_pathcurrent_release
  • rm -rf /tmp/*
  • 在以下时间后运行任务bundler:config
after "bundler:config", "deploy:checkout_subdir"

namespace :deploy do
  task :checkout_subdir do
    on roles :all do
      execute "mv #{release_path}/backend/ /tmp && rm -rf #{release_path}/* && mv /tmp/backend/* #{release_path} && rm -rf /tmp/*"
    end
  end
end