在 Capistrano 中部署 Git 子目录

发布于 2024-12-08 11:37:09 字数 298 浏览 0 评论 0原文

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

/ <-- 顶级

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

/server < -- Rails 应用程序

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

My master branch layout is like this:

/ <-- top level

/client <-- desktop client source files

/server <-- Rails app

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

手心的温暖 2024-12-15 11:37:10

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

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

Without any dirty forking action but even dirtier !

In my config/deploy.rb :

set :deploy_subdir, "project/subdir"

Then I added this new strategy to my 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)
老子叫无熙 2024-12-15 11:37:10

对于 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 参数来提取存档正确的水平。

更新

从 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

For Capistrano 3.0, I use the following:

In my 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:

# 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 release method, which uses git archive to archive only a subdirectory of the repo, then uses the --strip argument to tar to extract the archive at the right level.

UPDATE

As of Capistrano 3.3.3, you can now use the :repo_tree configuration variable, which makes this answer obsolete. For example:

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.

故人的歌 2024-12-15 11:37:10

我们还通过 Capistrano 克隆完整的存储库、删除未使用的文件和文件夹并将所需的文件夹向上移动到层次结构中来实现此目的。

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 子模块分组在一起

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.

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.

回首观望 2024-12-15 11:37:10

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

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

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).

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.

撕心裂肺的伤痛 2024-12-15 11:37:10

有一个解决方案。获取 crdlo 的 capistrano 补丁 和 <来自 github 的 href="http://github.com/jamis/capistrano/tree/master" rel="nofollow noreferrer">capistrano 源。删除现有的 capistrano gem,应用补丁,setup.rb 安装,然后你可以使用他非常简单的配置行 set :project, "mysubdirectory" 来设置子目录。

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

另请参阅是否可以让 capistrano 作者将此功能添加到 cap 相关错误

There is a solution. Grab crdlo's patch for capistrano and the capistrano source from 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.

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.

Also see if you can get capistrano authors to add this feature into cap at the relevant bug.

自演自醉 2024-12-15 11:37: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"

For Capistrano 3, based on @Thomas Fankhauser answer:

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"
深居我梦 2024-12-15 11:37:10

使用 capistrano 3.17.3,下面的解决方案对我有用,它受到 Thomas Fankhauser 的解决方案的启发,

  • 使用 release_path 而不是 current_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

With capistrano 3.17.3 the solution bellow worked for me, it was inspired in the solution from Thomas Fankhauser

  • use release_path instead of current_release
  • add rm -rf /tmp/*
  • run the task after 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

韶华倾负 2024-12-15 11:37:10

不幸的是,git 没有提供这样做的方法。相反,“git 方式”是拥有两个存储库——客户端和服务器,然后克隆您需要的存储库。

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.

梦中楼上月下 2024-12-15 11:37:10

我根据之前的答案和 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

I created a snipped that works with Capistrano 3.x based in previous anwers and other information found in 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

It's also available as a Gist on Github.

小草泠泠 2024-12-15 11:37:10

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

https://capistranorb.com/documentation/getting-started/配置/

dont know if anyone is still interested on this. but just letting you guys if anyone is looking for an answer.
now we can use: :repo_tree

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

野心澎湃 2024-12-15 11:37:10

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

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

驱逐舰岛风号 2024-12-15 11:37:10

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

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

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

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).

Let's see how robust it is. Using "before" is pretty weak.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文