├── .gitignore ├── .rspec ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── bin └── git-copy ├── cli-test.sh ├── git-copy.gemspec ├── lib └── git-copy.rb └── spec ├── git_copy_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /test/tmp/ 9 | /test/version_tmp/ 10 | /tmp/ 11 | 12 | ## Specific to RubyMotion: 13 | .dat* 14 | .repl_history 15 | build/ 16 | 17 | ## Documentation cache and generated files: 18 | /.yardoc/ 19 | /_yardoc/ 20 | /doc/ 21 | /rdoc/ 22 | 23 | ## Environment normalisation: 24 | /.bundle/ 25 | /lib/bundler/man/ 26 | 27 | # for a library or gem, you might want to ignore these files since the code is 28 | # intended to run in multiple environments; otherwise, check them in: 29 | # Gemfile.lock 30 | # .ruby-version 31 | # .ruby-gemset 32 | 33 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 34 | .rvmrc 35 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.0.0 4 | - 2.1.0 5 | script: 6 | - rake spec 7 | - ./cli-test.sh 8 | deploy: 9 | provider: rubygems 10 | api_key: 11 | secure: iLK75fek/gb6iDaEzOB44npnoWdiOwjiM/kx1xKGVOVGwyRGbLo0doZh+wnDz2GBdvzJTlaWmHDtCovhCTShNsbTlvRBf9gNg1TwDQmed5NqokEpSPESiCaJSTwTYYCafpRVgEXxtYDb/O6rfsLKptfKsc6OKdRJNKwzblsgzlI= 12 | on: 13 | repo: cybertk/git-copy 14 | tags: true 15 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'rspec', '~> 3.0' 4 | gem 'rake' 5 | gem 'addressable', '~> 2.3' 6 | gem 'git', '~> 1.2' 7 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.3.8) 5 | diff-lcs (1.2.5) 6 | git (1.2.9.1) 7 | rake (10.4.0) 8 | rspec (3.2.0) 9 | rspec-core (~> 3.2.0) 10 | rspec-expectations (~> 3.2.0) 11 | rspec-mocks (~> 3.2.0) 12 | rspec-core (3.2.2) 13 | rspec-support (~> 3.2.0) 14 | rspec-expectations (3.2.0) 15 | diff-lcs (>= 1.2.0, < 2.0) 16 | rspec-support (~> 3.2.0) 17 | rspec-mocks (3.2.1) 18 | diff-lcs (>= 1.2.0, < 2.0) 19 | rspec-support (~> 3.2.0) 20 | rspec-support (3.2.2) 21 | 22 | PLATFORMS 23 | ruby 24 | 25 | DEPENDENCIES 26 | addressable (~> 2.3) 27 | git (~> 1.2) 28 | rake 29 | rspec (~> 3.0) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## git-copy 2 | 3 | > Git plugin for copy remote/local git repo to another remote/local destination 4 | 5 | [![Gem](https://img.shields.io/gem/v/git-copy.svg)](https://rubygems.org/gems/git-copy) 6 | [![Build Status](https://travis-ci.org/cybertk/git-copy.svg?branch=master)](https://travis-ci.org/cybertk/git-copy) 7 | [![Dependency Status](https://gemnasium.com/cybertk/git-copy.svg)](https://gemnasium.com/cybertk/git-copy) 8 | 9 | ## Getting Started 10 | 11 | sudo gem install git-copy 12 | git copy https://github.com/cybertk/git-copy.git https://github.com/cybertk/git-copy.git 13 | 14 | ### Examples 15 | 16 | Copy this repo to a local hosted git server 17 | 18 | git init --bare git-copy.git 19 | git copy https://github.com/cybertk/git-copy.git $PWD/git-copy.git 20 | 21 | ## Contribution 22 | 23 | Any contribution is more then welcome! 24 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | begin 2 | require 'rspec/core/rake_task' 3 | RSpec::Core::RakeTask.new(:spec) 4 | rescue LoadError 5 | end 6 | 7 | task :default => :spec 8 | -------------------------------------------------------------------------------- /bin/git-copy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | $LOAD_PATH.unshift(File.dirname(File.realpath(__FILE__)) + '/../lib') 5 | 6 | require "optparse" 7 | require 'git-copy' 8 | 9 | options = {} 10 | optparse = OptionParser.new do |opts| 11 | opts.banner = "Usage: git copy " 12 | opts.on("-h", "--help", "Display this screen") do 13 | puts opts 14 | exit 15 | end 16 | 17 | opts.on_tail("--version", "Show version") do 18 | puts ::Version.join(".") 19 | exit 20 | end 21 | 22 | if ARGV.size != 2 then 23 | puts "You must specify source and destination repositories." 24 | puts "" 25 | puts opts 26 | exit 27 | end 28 | end.parse! 29 | 30 | Git.copy(ARGV[0], ARGV[1]) 31 | -------------------------------------------------------------------------------- /cli-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | echo when build Gem 6 | gem build git-copy.gemspec 7 | 8 | echo when install Gem 9 | gem install git-copy-*.gem 10 | 11 | echo when call git-copy 12 | git copy 13 | -------------------------------------------------------------------------------- /git-copy.gemspec: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path("../lib", __FILE__) 2 | 3 | Gem::Specification.new do |spec| 4 | spec.name = "git-copy" 5 | spec.version = "0.2.1" 6 | 7 | spec.author = "Quanlong He" 8 | spec.email = "kyan.ql.he@gmail.com" 9 | spec.homepage = "https://github.com/cybertk/git-copy" 10 | spec.summary = "Copy git repo to another destination" 11 | spec.description = "Git plugin for copy remote/local git repo to another remote/local destination" 12 | spec.executables = "git-copy" 13 | spec.license = "MIT" 14 | 15 | spec.files = Dir["lib/**/*"] + %w{ bin/git-copy README.md LICENSE } 16 | 17 | spec.add_runtime_dependency('addressable', '~> 2.3') 18 | end 19 | -------------------------------------------------------------------------------- /lib/git-copy.rb: -------------------------------------------------------------------------------- 1 | require 'tmpdir' 2 | require 'addressable/uri' 3 | 4 | module Git 5 | 6 | def self.copy(src, dst) 7 | # Copy a remote git repo to another remote destination 8 | # 9 | # Example: 10 | # >> GitCopy("https://github.com/cybertk/git-copy", "https://bitbucket.com/mirror.git") 11 | # >> GitCopy("https://github.com/cybertk/git-copy", "mirror.git") 12 | uri = Addressable::URI.parse(dst) 13 | 14 | # Convert to absolute path for local path 15 | dst = File.absolute_path(dst) unless uri.scheme 16 | 17 | if uri.scheme || File.exist?(dst) 18 | 19 | Dir.mktmpdir('git-copy-') do |dir| 20 | # Clone source into temp working dir 21 | unless `git clone --bare #{src} #{dir}`.to_i == 0 22 | raise 'git clone faild' 23 | end 24 | 25 | unless `cd #{dir}; git push -f --mirror #{dst}`.to_i == 0 26 | raise 'git push faild' 27 | end 28 | end 29 | else 30 | # Copy to local path 31 | unless `git clone --bare #{src} #{dst}`.to_i == 0 32 | raise 'git clone failed' 33 | end 34 | end 35 | 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /spec/git_copy_spec.rb: -------------------------------------------------------------------------------- 1 | require 'git-copy' 2 | require 'git' 3 | 4 | describe 'when copy to un-exist local repo' do 5 | before(:each) do 6 | @dst_repo = 'local.repo' 7 | expect(File.exist? @dst_repo).to be false 8 | end 9 | 10 | after(:each) do 11 | FileUtils.rm_rf @dst_repo 12 | end 13 | 14 | it 'from http, should succeed' do 15 | Git.copy('http://github.com/cybertk/git-copy', 'local.repo') 16 | 17 | g = Git.bare('local.repo') 18 | expect(g.tag('v0.2.0').sha).to eq('29181737e23646e80733afa0c1109a62bd65653b') 19 | end 20 | 21 | it 'from https, should succeed' do 22 | Git.copy('https://github.com/cybertk/git-copy', 'local.repo') 23 | 24 | g = Git.bare('local.repo') 25 | expect(g.tag('v0.2.0').sha).to eq('29181737e23646e80733afa0c1109a62bd65653b') 26 | end 27 | 28 | it 'from local, should succeed' do 29 | Git.copy('.', 'local.repo') 30 | 31 | g = Git.bare('local.repo') 32 | expect(g.tag('v0.2.0').sha).to eq('29181737e23646e80733afa0c1109a62bd65653b') 33 | end 34 | end 35 | 36 | describe 'when copy to exist local bare repo' do 37 | before(:each) do 38 | @dst_repo = 'bare.repo' 39 | g = Git.init '.', repository: @dst_repo, bare: true 40 | end 41 | 42 | after(:each) do 43 | FileUtils.rm_rf @dst_repo 44 | end 45 | 46 | it 'from local, should succeed' do 47 | Git.copy('.', @dst_repo) 48 | 49 | g = Git.bare(@dst_repo) 50 | # expect(g.tag('v0.2.0').sha).to eq('29181737e23646e80733afa0c1109a62bd65653b') 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rspec --init` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # The `.rspec` file also contains a few flags that are not defaults but that 16 | # users commonly want. 17 | # 18 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 19 | RSpec.configure do |config| 20 | # rspec-expectations config goes here. You can use an alternate 21 | # assertion/expectation library such as wrong or the stdlib/minitest 22 | # assertions if you prefer. 23 | config.expect_with :rspec do |expectations| 24 | # This option will default to `true` in RSpec 4. It makes the `description` 25 | # and `failure_message` of custom matchers include text for helper methods 26 | # defined using `chain`, e.g.: 27 | # be_bigger_than(2).and_smaller_than(4).description 28 | # # => "be bigger than 2 and smaller than 4" 29 | # ...rather than: 30 | # # => "be bigger than 2" 31 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 32 | end 33 | 34 | # rspec-mocks config goes here. You can use an alternate test double 35 | # library (such as bogus or mocha) by changing the `mock_with` option here. 36 | config.mock_with :rspec do |mocks| 37 | # Prevents you from mocking or stubbing a method that does not exist on 38 | # a real object. This is generally recommended, and will default to 39 | # `true` in RSpec 4. 40 | mocks.verify_partial_doubles = true 41 | end 42 | 43 | # The settings below are suggested to provide a good initial experience 44 | # with RSpec, but feel free to customize to your heart's content. 45 | =begin 46 | # These two settings work together to allow you to limit a spec run 47 | # to individual examples or groups you care about by tagging them with 48 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 49 | # get run. 50 | config.filter_run :focus 51 | config.run_all_when_everything_filtered = true 52 | 53 | # Limits the available syntax to the non-monkey patched syntax that is 54 | # recommended. For more details, see: 55 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 56 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 57 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 58 | config.disable_monkey_patching! 59 | 60 | # This setting enables warnings. It's recommended, but in some cases may 61 | # be too noisy due to issues in dependencies. 62 | config.warnings = true 63 | 64 | # Many RSpec users commonly either run the entire suite or an individual 65 | # file, and it's useful to allow more verbose output when running an 66 | # individual spec file. 67 | if config.files_to_run.one? 68 | # Use the documentation formatter for detailed output, 69 | # unless a formatter has already been configured 70 | # (e.g. via a command-line flag). 71 | config.default_formatter = 'doc' 72 | end 73 | 74 | # Print the 10 slowest examples and example groups at the 75 | # end of the spec run, to help surface which specs are running 76 | # particularly slow. 77 | config.profile_examples = 10 78 | 79 | # Run specs in random order to surface order dependencies. If you find an 80 | # order dependency and want to debug it, you can fix the order by providing 81 | # the seed, which is printed after each run. 82 | # --seed 1234 83 | config.order = :random 84 | 85 | # Seed global randomization in this process using the `--seed` CLI option. 86 | # Setting this allows you to use `--seed` to deterministically reproduce 87 | # test failures related to randomization by passing the same `--seed` value 88 | # as the one that triggered the failure. 89 | Kernel.srand config.seed 90 | =end 91 | end 92 | --------------------------------------------------------------------------------