git_commands 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 00a6f3b64ac568ed9a8a00e28c157015f70a5892
4
+ data.tar.gz: deeb00dac84552dd33e4f8bfde79aaae31d8ee90
5
+ SHA512:
6
+ metadata.gz: dd423813e1be43a52b56011ef9c49540b759342e04fca35981967b618166c8613a1ac4eff440b69bebaabcaa0bee6ce1edd15850220e704d239b206a47cef16a
7
+ data.tar.gz: 44a626d66746877bb03092572b74541858607a81f698d46e69887747660f6f181a48f4b36e43c16a62fcac1dc0dec6a3a55f9dafb66e2774f5d9b8590a3d00f5
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ /.vagrant/
2
+ /.bundle/
3
+ .branches
4
+ Gemfile.lock
5
+ *.gem
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.8
8
+ - 2.2.1
9
+ - 2.3.0
10
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dacom.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Michele Costa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ 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, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ ## Table of Contents
2
+ * [Workflow](#workflow)
3
+ * [Scope](#scope)
4
+ * [Installation](#installation)
5
+ * [Usage](#usage)
6
+ * [setup](#setup)
7
+ * [rebase](#rebase)
8
+ * [purge](#purge)
9
+ * [aggregate](#aggregate)
10
+
11
+ ## Workflow
12
+ This script will facilitate adopting a subset of the branch-featuring workflow characterised by:
13
+ * each **feature** will have **its own branch**
14
+ * **feature** branches **derive** directly **form master**
15
+ * **integration** of master to feature branch happens **via rebasing**
16
+ * rebasing interactively is used on feature branch to **squash commits** to get a **single one per feature** branch
17
+ * **pushing with force** on local branches is not an issue
18
+ * **release** branches are created **aggregating multiple branches** into a new one
19
+
20
+ ## Scope
21
+ The scope of this is helping out in the following cases:
22
+ * you have multiple feature branches waiting for release due to some reason (i.e. long QA time...), and need to keep them aligned with master
23
+ * you need to quickly aggregate branches for a release
24
+
25
+ ## Installation
26
+ I assume you have GIT installed ;)
27
+ You will probably use this gem standalone, since i see no use in including it into another project.
28
+ Just clone the Github repository, move to the gem directory and start using rake tasks.
29
+
30
+ ## Usage
31
+ Here are the main Rake tasks:
32
+
33
+ ### setup
34
+ The core of the library is automating multiple branches fetching, this action happens in two concurrent ways:
35
+ * from the command line, by splitting a comma separated list
36
+ * by reading a file where names are listed on each line
37
+ In case **no branches** are fetched the **script halts**.
38
+
39
+ Is also assumed you're pointing to a project directory somewhere, so the script could move in and execute the GIT commands for you.
40
+
41
+ To call this task with arguments call it like that:
42
+ ```ruby
43
+ rake git_commands:setup repo=git_repository base_dir=repo_path branches_file=file_listing_branches branches=list,of,branches,separated,by,comma
44
+ ```
45
+ Here are the arguments list:
46
+ * **repo**: the repository name you want to automate git commant to
47
+ * **base_dir**: the base path to your GIT repo, excluding its name (specified eralier). It defaults to HOME/Sites
48
+ * **branches_file**: the path to the file, if any, listing the branches names. It defaults to the **.branches** file inside of your repo path (you need to add it to the .gitignore then)
49
+ * **branches**: a list of branches separated by comma (optional), if specified it has precedence over the branches_file
50
+
51
+ ### rebase
52
+ This is probably the most useful command in case you have several branch to rebase with _origin/master_ frequently.
53
+ Consider after the rebase the branch is pushed to origin with force, so be aware in case more than one programmer access the same branch from different computers.
54
+ A confirmation is asked to continue.
55
+
56
+ As the other tasks, it depends on the setup one, so it accepts the same arguments:
57
+ ```ruby
58
+ # loads branches from the repo .branches file, repo si located at HOME/Sites/my_repo
59
+ rake git_commands:rebase repo=my_repo
60
+ ```
61
+
62
+ ### purge
63
+ This command remove the specified branches locally and remotely.
64
+ A confirmation is asked before each removal.
65
+ It uses the same arguments as setup:
66
+ ```ruby
67
+ # purge old branches specified at the command line, repo is located at HOME/Sites/my_repo
68
+ rake git_commands:purge repo=my_repo branches=old_branch,older_branch,oldest_branch
69
+ ```
70
+
71
+ ### aggregate
72
+ It should be useful to aggregate your branches into a single one in case you want to create a release branch.
73
+ It uses the following naming convention: rb_yyyy_mm_dd
74
+ A confirmation is asked to continue.
75
+ It uses the same arguments as setup:
76
+ ```ruby
77
+ # aggregate branches listed in the /tmp/to_release file, repo si located at HOME/Sites/my_repo
78
+ rake git_commands:aggregate repo=my_repo branches_file=/tmp/to_release
79
+ ```
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ import 'lib/tasks/git_commands.rake'
4
+
5
+ Rake::TestTask.new(:spec) do |t|
6
+ t.libs << 'lib'
7
+ t.libs << 'spec'
8
+ t.test_files = FileList['spec/*_spec.rb']
9
+ end
10
+
11
+ task :default => :spec
data/Vagrantfile ADDED
@@ -0,0 +1,80 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ # All Vagrant configuration is done below. The "2" in Vagrant.configure
5
+ # configures the configuration version (we support older styles for
6
+ # backwards compatibility). Please don't change it unless you know what
7
+ # you're doing.
8
+ Vagrant.configure(2) do |config|
9
+ # The most common configuration options are documented and commented below.
10
+ # For a complete reference, please see the online documentation at
11
+ # https://docs.vagrantup.com.
12
+
13
+ # Every Vagrant development environment requires a box. You can search for
14
+ # boxes at https://atlas.hashicorp.com/search.
15
+ config.vm.box = "ubuntu/trusty64"
16
+
17
+ # Disable automatic box update checking. If you disable this, then
18
+ # boxes will only be checked for updates when the user runs
19
+ # `vagrant box outdated`. This is not recommended.
20
+ config.vm.box_check_update = false
21
+
22
+ # Create a forwarded port mapping which allows access to a specific port
23
+ # within the machine from a port on the host machine. In the example below,
24
+ # accessing "localhost:8080" will access port 80 on the guest machine.
25
+ # config.vm.network "forwarded_port", guest: 80, host: 8080
26
+
27
+ # Create a private network, which allows host-only access to the machine
28
+ # using a specific IP.
29
+ config.vm.network "private_network", ip: "192.168.33.22"
30
+
31
+ # Create a public network, which generally matched to bridged network.
32
+ # Bridged networks make the machine appear as another physical device on
33
+ # your network.
34
+ # config.vm.network "public_network"
35
+
36
+ # Share an additional folder to the guest VM. The first argument is
37
+ # the path on the host to the actual folder. The second argument is
38
+ # the path on the guest to mount the folder. And the optional third
39
+ # argument is a set of non-required options.
40
+ # config.vm.synced_folder "../data", "/vagrant_data"
41
+
42
+ # Provider-specific configuration so you can fine-tune various
43
+ # backing providers for Vagrant. These expose provider-specific options.
44
+ # Example for VirtualBox:
45
+ #
46
+ config.vm.provider "virtualbox" do |vb|
47
+ # Display the VirtualBox GUI when booting the machine
48
+ #vb.gui = true
49
+
50
+ # Customize the amount of memory on the VM:
51
+ vb.memory = "6144"
52
+ vb.cpus = 3
53
+ end
54
+ #
55
+ # View the documentation for the provider you are using for more
56
+ # information on available options.
57
+
58
+ # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
59
+ # such as FTP and Heroku are also available. See the documentation at
60
+ # https://docs.vagrantup.com/v2/push/atlas.html for more information.
61
+ # config.push.define "atlas" do |push|
62
+ # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
63
+ # end
64
+
65
+ # Enable provisioning with a shell script. Additional provisioners such as
66
+ # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
67
+ # documentation for more information about their specific syntax and use.
68
+ # config.vm.provision "shell", inline: <<-SHELL
69
+ # sudo apt-get update
70
+ # sudo apt-get install -y apache2
71
+ # SHELL
72
+ $script = [
73
+ "sudo apt-add-repository ppa:brightbox/ruby-ng",
74
+ "sudo apt-get update",
75
+ "sudo apt-get -y -q install build-essential libssl-dev git",
76
+ "sudo apt-get -y -q install ruby2.2 ruby2.2-dev",
77
+ "sudo gem install bundler"]
78
+
79
+ config.vm.provision "shell", inline: $script.join(" && ")
80
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "git_utils"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git_commands/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "git_commands"
8
+ s.version = GitCommands::VERSION
9
+ s.authors = ["costajob"]
10
+ s.email = ["costajob@gmail.com"]
11
+ s.summary = "Utility library to rebase and aggregate your project branches"
12
+ s.homepage = "https://github.com/costajob/git_commands.git"
13
+ s.license = "MIT"
14
+ s.required_ruby_version = ">= 1.9.2"
15
+
16
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|s|features)/}) }
17
+ s.bindir = "exe"
18
+ s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "bundler", "~> 1.11"
22
+ s.add_development_dependency "rake", "~> 10.0"
23
+ s.add_development_dependency "minitest", "~> 5.0"
24
+ s.add_development_dependency "rr", "~> 1.2"
25
+ end
@@ -0,0 +1 @@
1
+ require 'git_commands/command'
@@ -0,0 +1,22 @@
1
+ module GitCommands
2
+ module Colorize
3
+ CODES = {
4
+ :red => 31,
5
+ :green => 32,
6
+ :yellow => 33,
7
+ :blue => 34,
8
+ :magenta => 35,
9
+ :cyan => 36,
10
+ :grey => 37
11
+ }
12
+
13
+ end
14
+ end
15
+
16
+ String.instance_eval do
17
+ GitCommands::Colorize::CODES.each do |message, code|
18
+ define_method(message) do
19
+ "\e[#{code}m#{self}\e[0m"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,135 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+ require 'net/http'
4
+ require 'git_commands/prompt'
5
+
6
+ module GitCommands
7
+ class Command
8
+ include Prompt
9
+
10
+ class GitError < StandardError; end
11
+ class NoBranchesError < StandardError; end
12
+
13
+ GITHUB_HOST = 'github.com'
14
+ BASE_DIR = File.join(ENV['HOME'], 'Sites')
15
+ UNFINISHED_REBASE_FILES = %w(rebase-merge rebase-apply)
16
+
17
+ def self.check_connection
18
+ !!Net::HTTP.new(GITHUB_HOST).head('/')
19
+ rescue Errno::ENETUNREACH => e
20
+ raise e, 'There is no connection!'
21
+ end
22
+
23
+ def initialize(options = {})
24
+ self.class.check_connection
25
+ @repo = options[:repo] || error('Please specify a valid repository name!', ArgumentError)
26
+ @base_dir = options[:base_dir] || BASE_DIR
27
+ @branches_file = options[:branches_file] || repo_path.join('.branches')
28
+ @branches = options[:branches].to_s.split(',')
29
+ fetch_branches
30
+ check_branches
31
+ end
32
+
33
+ def purge
34
+ enter_repo do
35
+ @branches.each do |branch|
36
+ error('Trying ro remove master!', GitError) if branch == 'master'
37
+ warning("Removing branch: #{branch}")
38
+ confirm('Remove local branch') do
39
+ `git branch -D #{branch}`
40
+ end
41
+ confirm('Remove remote branch') do
42
+ `git push origin :#{branch}`
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def rebase
49
+ confirm('Proceed rebasing these branches') do
50
+ enter_repo do
51
+ @branches.each do |branch|
52
+ warning("Rebasing branch: #{branch}")
53
+ `git checkout #{branch}`
54
+ `git pull origin #{branch}`
55
+ rebase_with_master
56
+ `git push origin #{branch} -f`
57
+ `git checkout master`
58
+ `git branch -D #{branch}`
59
+ success 'Rebased successfully!'
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def aggregate
66
+ temp = "temp_#{aggregate_name}"
67
+ confirm("Aggregate branches into #{aggregate_name}") do
68
+ enter_repo do
69
+ `git branch #{aggregate_name}`
70
+ @branches.each do |branch|
71
+ warning("Merging branch: #{branch}")
72
+ `git checkout -b #{temp} origin/#{branch} --no-track`
73
+ rebase_with_master
74
+ `git rebase #{aggregate_name}`
75
+ `git checkout #{aggregate_name}`
76
+ `git merge #{temp}`
77
+ `git branch -d #{temp}`
78
+ end
79
+ end
80
+ success 'Aggregate branch created'
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def repo_path
87
+ @repo_path ||= Pathname::new(File.join(@base_dir, @repo))
88
+ end
89
+
90
+ def fetch_branches
91
+ return unless @branches.empty? && File.exist?(@branches_file)
92
+ warning('Loading branches file')
93
+ @branches = File.foreach(@branches_file).map(&:strip)
94
+ end
95
+
96
+ def check_branches
97
+ error('No branches have been loaded!', NoBranchesError) if @branches.empty?
98
+ print_branches
99
+ end
100
+
101
+ def print_branches
102
+ size = @branches.to_a.size
103
+ plural = size > 1 ? 'es' : ''
104
+ success "Successfully loaded #{size} branch#{plural}:"
105
+ puts @branches.each_with_index.map { |branch, i| "#{(i+1).to_s.rjust(2, '0')}. #{branch}" } + ['']
106
+ end
107
+
108
+ def pull_master
109
+ `git checkout master`
110
+ `git pull`
111
+ end
112
+
113
+ def rebase_with_master
114
+ `git rebase origin/master`
115
+ error('Halting unfinished rebase!', GitError) { `git rebase --abort` } if unfinished_rebase?
116
+ end
117
+
118
+ def enter_repo
119
+ Dir.chdir repo_path do
120
+ pull_master
121
+ yield
122
+ end
123
+ end
124
+
125
+ def unfinished_rebase?
126
+ UNFINISHED_REBASE_FILES.any? do |name|
127
+ File.exists?(repo_path.join('.git', name))
128
+ end
129
+ end
130
+
131
+ def aggregate_name
132
+ @aggregate_name ||= Time.new.strftime("rb_%Y-%m-%d")
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,47 @@
1
+ require 'git_commands/colorize'
2
+
3
+ module GitCommands
4
+ module Prompt
5
+ VALID_ANSWERS = %w[Y y N n]
6
+
7
+ class AbortError < StandardError; end
8
+
9
+ def warning(message, char = '*')
10
+ spacer = (char * (message.size + 4)).grey
11
+ puts "\n", spacer, "#{char} #{message.to_s.yellow} #{char}", spacer, "\n"
12
+ end
13
+
14
+ def error(message, error = StandardError)
15
+ puts message.to_s.red
16
+ yield if block_given?
17
+ fail error, message
18
+ end
19
+
20
+ def success(message)
21
+ puts message.to_s.green
22
+ end
23
+
24
+ def confirm(message)
25
+ res = begin
26
+ ask "#{message} (Y/N)?"
27
+ end until VALID_ANSWERS.include?(res)
28
+ case res
29
+ when /y/i
30
+ yield
31
+ else
32
+ error('Aborted operation!', AbortError)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def ask(message)
39
+ print message.cyan
40
+ input
41
+ end
42
+
43
+ def input
44
+ STDIN.gets.chomp
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ module GitCommands
2
+ VERSION = "2.1.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ require 'git_commands/command'
2
+
3
+ namespace :git_commands do
4
+ desc <<END
5
+ Setup the command instance:
6
+ > rake git_utils:setup repo=git_repository base_dir=repo_path branches_file=file_listing_branches branches=list,of,branches,separated,by,comma
7
+ END
8
+ task :setup do
9
+ @command = GitCommands::Command::new(:repo => ENV['repo'],
10
+ :base_dir => ENV['base_dir'],
11
+ :branches_file => ENV['branches_file'],
12
+ :branches => ENV['branches'])
13
+ end
14
+
15
+ desc 'Purge specified branches locally and from origin'
16
+ task :purge => :setup do
17
+ @command.purge
18
+ end
19
+
20
+ desc 'Rebase specified branches with master'
21
+ task :rebase => :setup do
22
+ @command.rebase
23
+ end
24
+
25
+ desc 'Aggregate specified branches into a single one'
26
+ task :aggregate => :setup do
27
+ @command.aggregate
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git_commands
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.1.0
5
+ platform: ruby
6
+ authors:
7
+ - costajob
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-09-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rr
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.2'
69
+ description:
70
+ email:
71
+ - costajob@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - Vagrantfile
83
+ - bin/console
84
+ - bin/setup
85
+ - git_commands.gemspec
86
+ - lib/git_commands.rb
87
+ - lib/git_commands/colorize.rb
88
+ - lib/git_commands/command.rb
89
+ - lib/git_commands/prompt.rb
90
+ - lib/git_commands/version.rb
91
+ - lib/tasks/git_commands.rake
92
+ homepage: https://github.com/costajob/git_commands.git
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 1.9.2
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.5.1
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Utility library to rebase and aggregate your project branches
116
+ test_files: []