Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Distributed git support for better operability with remote_cache stra…

…tegy (closes #11137)

git-svn-id: http://svn.rubyonrails.org/rails/tools/capistrano@8923 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit a06a802168fcb0fa013b25e5b297e3ed6c5ed06f 1 parent 1ace9cb
@jamis jamis authored
View
2  CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Distributed git support for better operability with remote_cache strategy [voidlock]
+
* Use a default line length in help text if line length is otherwise too small [Jamis Buck]
* Fix incorrect reference to the 'setup' task in task documentation [rajeshduggal]
View
80 lib/capistrano/recipes/deploy/scm/git.rb
@@ -49,11 +49,28 @@ module SCM
# You may set <tt>:branch</tt>, which is the reference to the branch, tag,
# or any SHA1 you are deploying, for example:
#
- # set :branch, "origin/master"
+ # set :branch, "master"
#
# Otherwise, HEAD is assumed. I strongly suggest you set this. HEAD is
# not always the best assumption.
#
+ # You may also set <tt>:remote</tt>, which will be used as a name for remote
+ # tracking of repositories. This option is intended for use with the
+ # <tt>:remote_cache</tt> strategy in a distributed git environment.
+ #
+ # For example in the projects <tt>config/deploy.rb</tt>:
+ #
+ # set :repository, "#{scm_user}@somehost:~/projects/project.git"
+ # set :remote, "#{scm_user}"
+ #
+ # Then each person with deploy priveledges can add the following to their
+ # local <tt>~/.caprc</tt> file:
+ #
+ # set :scm_user, 'someuser'
+ #
+ # Now any time a person deploys the project, their repository will be
+ # setup as a remote git repository within the cached repository.
+ #
# The <tt>:scm_command</tt> configuration variable, if specified, will
# be used as the full path to the git executable on the *remote* machine:
#
@@ -78,7 +95,7 @@ module SCM
# set :deploy_via, :remote_cache
#
# For faster clone, you can also use shallow cloning. This will set the
- # '--depth' flag using the depth specified. This *cannot* be used
+ # '--depth' flag using the depth specified. This *cannot* be used
# together with the :remote_cache strategy
#
# set :git_shallow_clone, 1
@@ -88,8 +105,9 @@ module SCM
#
# Garry Dolley http://scie.nti.st
# Contributions by Geoffrey Grosenbach http://topfunky.com
- # and Scott Chacon http://jointheconversation.org
-
+ # Scott Chacon http://jointheconversation.org
+ # and Alex Arnell http://twologic.com
+
class Git < Base
# Sets the default command name for this SCM on your *local* machine.
# Users may override this by setting the :scm_command variable.
@@ -102,27 +120,35 @@ def head
configuration[:branch] || 'HEAD'
end
+ def origin
+ configuration[:remote] || 'origin'
+ end
+
# Performs a clone on the remote machine, then checkout on the branch
# you want to deploy.
def checkout(revision, destination)
- git = command
+ git = command
+ remote = origin
- branch = head
-
- fail "No branch specified, use for example 'set :branch, \"origin/master\"' in your deploy.rb" unless branch
+ args = []
+ args << "-o #{remote}" unless remote == 'origin'
+ if depth = configuration[:git_shallow_clone]
+ args << "--depth #{depth}"
+ end
execute = []
- if depth = configuration[:git_shallow_clone]
- execute << "#{git} clone --depth #{depth} #{configuration[:repository]} #{destination}"
+ if args.empty?
+ execute << "#{git} clone #{configuration[:repository]} #{destination}"
else
- execute << "#{git} clone #{configuration[:repository]} #{destination}"
+ execute << "#{git} clone #{args.join(' ')} #{configuration[:repository]} #{destination}"
end
- execute << "cd #{destination}"
- execute << "#{git} checkout #{branch}"
+ # checkout into a local branch rather than a detached HEAD
+ execute << "cd #{destination} && #{git} checkout -b deploy #{revision}"
+
if configuration[:git_enable_submodules]
- execute << "#{git} submodule init"
- execute << "#{git} submodule update"
+ execute << "#{git} submodule init"
+ execute << "#{git} submodule update"
end
execute.join(" && ")
@@ -131,16 +157,26 @@ def checkout(revision, destination)
# Merges the changes to 'head' since the last fetch, for remote_cache
# deployment strategy
def sync(revision, destination)
- git = command
+ git = command
+ remote = origin
+
execute = []
- execute << "cd #{destination} && #{git} fetch origin"
+ execute << "cd #{destination}"
- if head == 'HEAD'
- execute << "#{git} checkout origin/HEAD"
- else
- execute << "#{git} checkout #{head}"
+ # Use git-config to setup a remote tracking branches. Could use
+ # git-remote but it complains when a remote of the same name already
+ # exists, git-config will just silenty overwrite the setting every
+ # time. This could cause wierd-ness in the remote cache if the url
+ # changes between calls, but as long as the repositories are all
+ # based from each other it should still work fine.
+ if remote != 'origin'
+ execute << "#{git} config remote.#{remote}.url #{configuration[:repository]}"
+ execute << "#{git} config remote.#{remote}.fetch +refs/heads/*:refs/remotes/#{remote}/*"
end
-
+
+ # since we're in a local branch already, just reset to specified revision rather than merge
+ execute << "#{git} fetch #{remote} && #{git} reset --hard #{revision}"
+
if configuration[:git_enable_submodules]
execute << "#{git} submodule update"
end
View
54 test/deploy/scm/git_test.rb
@@ -19,14 +19,21 @@ def test_head
assert_equal "master", @source.head
end
+ def origin
+ asser_equal "origin", @source.origin
+ @config[:remote] = "git"
+ assert_equal "git", @source.origin
+ end
+
def test_checkout
@config[:repository] = "git@somehost.com:project.git"
dest = "/var/www"
- assert_equal "git clone git@somehost.com:project.git /var/www && cd /var/www && git checkout HEAD", @source.checkout('Not used', dest)
+ rev = 'c2d9e79'
+ assert_equal "git clone git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy #{rev}", @source.checkout(rev, dest)
# With branch
@config[:branch] = "origin/foo"
- assert_equal "git clone git@somehost.com:project.git /var/www && cd /var/www && git checkout origin/foo", @source.checkout('Not used', dest)
+ assert_equal "git clone git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy #{rev}", @source.checkout(rev, dest)
end
def test_diff
@@ -51,26 +58,55 @@ def test_command_should_be_backwards_compatible
def test_sync
dest = "/var/www"
- assert_equal "cd #{dest} && git fetch origin && git checkout origin/HEAD", @source.sync('Not used', dest)
+ rev = 'c2d9e79'
+ assert_equal "cd #{dest} && git fetch origin && git reset --hard #{rev}", @source.sync(rev, dest)
# With branch
- @config[:branch] = "origin/foo"
- assert_equal "cd #{dest} && git fetch origin && git checkout origin/foo", @source.sync('Not used', dest)
+ @config[:branch] = "foo"
+ rev = '92d9e79' # simulate rev change
+ assert_equal "cd #{dest} && git fetch origin && git reset --hard #{rev}", @source.sync(rev, dest)
# With :scm_command
- @config[:scm_command] = "/opt/local/bin/git"
- assert_equal "cd #{dest} && /opt/local/bin/git fetch origin && /opt/local/bin/git checkout origin/foo", @source.sync('Not used', dest)
+ git = "/opt/local/bin/git"
+ @config[:scm_command] = git
+ assert_equal "cd #{dest} && #{git} fetch origin && #{git} reset --hard #{rev}", @source.sync(rev, dest)
+ end
+
+ def test_sync_with_remote
+ dest = "/var/www"
+ rev = 'c2d9e79'
+ remote = "username"
+ repository = "git@somehost.com:project.git"
+
+ @config[:repository] = repository
+ @config[:remote] = remote
+
+ assert_equal "cd #{dest} && git config remote.#{remote}.url #{repository} && git config remote.#{remote}.fetch +refs/heads/*:refs/remotes/#{remote}/* && git fetch #{remote} && git reset --hard #{rev}", @source.sync(rev, dest)
end
def test_shallow_clone
@config[:repository] = "git@somehost.com:project.git"
@config[:git_shallow_clone] = 1
dest = "/var/www"
- assert_equal "git clone --depth 1 git@somehost.com:project.git /var/www && cd /var/www && git checkout HEAD", @source.checkout('Not used', dest)
+ rev = 'c2d9e79'
+ assert_equal "git clone --depth 1 git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy #{rev}", @source.checkout(rev, dest)
# With branch
@config[:branch] = "origin/foo"
- assert_equal "git clone --depth 1 git@somehost.com:project.git /var/www && cd /var/www && git checkout origin/foo", @source.checkout('Not used', dest)
+ rev = '92d9e79' # simulate rev change
+ assert_equal "git clone --depth 1 git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy #{rev}", @source.checkout(rev, dest)
+ end
+
+ def test_remote_clone
+ @config[:repository] = "git@somehost.com:project.git"
+ @config[:remote] = "username"
+ dest = "/var/www"
+ rev = 'c2d9e79'
+ assert_equal "git clone -o username git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy #{rev}", @source.checkout(rev, dest)
+
+ # With branch
+ @config[:branch] = "foo"
+ assert_equal "git clone -o username git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy #{rev}", @source.checkout(rev, dest)
end
# Tests from base_test.rb, makin' sure we didn't break anything up there!
Please sign in to comment.
Something went wrong with that request. Please try again.