git-process-lib 2.0.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/git-new-fb.gemspec CHANGED
@@ -1,20 +1,20 @@
1
1
  require File.expand_path('../lib/git-process/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ["Jim Moore"]
4
+ gem.authors = ['Jim Moore']
5
5
  gem.email = %w(moore.jim@gmail.com)
6
6
  gem.description = %q{Fetches the latest repository from the server, rebases/merges the current branch against the changes in the integration branch, then pushes the result up to a branch on the server of the same name. (Unless told not to.)}
7
7
  gem.summary = %q{Gets the latest changes that have happened on the integration branch, then pushes your changes to a feature branch on the server.}
8
- gem.homepage = "http://jdigger.github.com/git-process/"
9
- gem.license = 'ASL2'
8
+ gem.homepage = 'http://jdigger.github.com/git-process/'
9
+ gem.license = 'Apache-2.0'
10
10
 
11
- gem.add_dependency "git-process-lib", GitProc::Version::STRING
11
+ gem.add_dependency 'git-process-lib', GitProc::Version::STRING
12
12
 
13
- gem.files = %w(README.md LICENSE CHANGELOG.md bin/git-new-fb)
13
+ gem.files = %w(README.adoc LICENSE CHANGELOG.md bin/git-new-fb)
14
14
  gem.files << 'man/git-new-fb.1'
15
15
  gem.executables = ['git-new-fb']
16
- gem.name = "git-new-fb"
16
+ gem.name = 'git-new-fb'
17
17
  gem.version = GitProc::Version::STRING
18
18
  gem.platform = Gem::Platform::RUBY
19
- gem.required_ruby_version = '>= 1.8.7'
19
+ gem.required_ruby_version = '>= 2.0'
20
20
  end
@@ -1,29 +1,26 @@
1
1
  require File.expand_path('../lib/git-process/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ["Jim Moore"]
4
+ gem.authors = ['Jim Moore']
5
5
  gem.email = %w(moore.jim@gmail.com)
6
6
  gem.description = %q{The libraries for the git-process suite of tools}
7
7
  gem.summary = %q{The libraries for the git-process suite of tools}
8
- gem.homepage = "http://jdigger.github.com/git-process/"
9
- gem.license = 'ASL2'
8
+ gem.homepage = 'http://jdigger.github.com/git-process/'
9
+ gem.license = 'Apache-2.0'
10
10
 
11
- gem.add_dependency "octokit", "~> 1.24.0" # GitHub API
12
- gem.add_dependency "json", "~> 1.8"
13
- gem.add_dependency "multi_json", "~> 1.8"
14
- gem.add_dependency "trollop", "~> 1.16" # CLI options parser
15
- gem.add_dependency "highline", "1.6.13" # user CLI interaction. There is a bug in 1.6.14
16
- gem.add_dependency "addressable", "~> 2.3" # URI processing
17
- gem.add_dependency "gem-man", "~> 0.3" # man page support for Gems
18
-
19
- # lock down external dependency
20
- gem.add_dependency "faraday", "0.8.9"
11
+ gem.add_dependency 'octokit', '~> 4.3' # GitHub API
12
+ gem.add_dependency 'netrc', '~> 0.11'
13
+ gem.add_dependency 'json', '~> 1.8'
14
+ gem.add_dependency 'trollop', '~> 2.1' # CLI options parser
15
+ gem.add_dependency 'highline', '~> 1.7' # user CLI interaction
16
+ gem.add_dependency 'addressable', '>= 2.3.5', '< 2.4' # URI processing. 2.4 Changes URI parsing
17
+ gem.add_dependency 'gem-man', '~> 0.3' # man page support for Gems
21
18
 
22
19
  gem.files = `git ls-files`.split($\).delete_if { |f| f =~ /^\./ }
23
20
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
24
- gem.name = "git-process-lib"
21
+ gem.name = 'git-process-lib'
25
22
  gem.require_paths = %w(lib)
26
23
  gem.version = GitProc::Version::STRING
27
24
  gem.platform = Gem::Platform::RUBY
28
- gem.required_ruby_version = '>= 1.8.7'
25
+ gem.required_ruby_version = '>= 2.0'
29
26
  end
data/git-process.gemspec CHANGED
@@ -1,22 +1,22 @@
1
1
  require File.expand_path('../lib/git-process/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ["Jim Moore"]
4
+ gem.authors = ['Jim Moore']
5
5
  gem.email = %w(moore.jim@gmail.com)
6
6
  gem.description = %q{A set of scripts to make working with git easier and more consistent}
7
7
  gem.summary = %q{A set of scripts for a good git process}
8
- gem.homepage = "http://jdigger.github.com/git-process/"
9
- gem.license = 'ASL2'
8
+ gem.homepage = 'http://jdigger.github.com/git-process/'
9
+ gem.license = 'Apache-2.0'
10
10
 
11
- gem.add_dependency "git-sync", GitProc::Version::STRING
12
- gem.add_dependency "git-new-fb", GitProc::Version::STRING
13
- gem.add_dependency "git-to-master", GitProc::Version::STRING
14
- gem.add_dependency "git-pull-req", GitProc::Version::STRING
11
+ gem.add_dependency 'git-sync', GitProc::Version::STRING
12
+ gem.add_dependency 'git-new-fb', GitProc::Version::STRING
13
+ gem.add_dependency 'git-to-master', GitProc::Version::STRING
14
+ gem.add_dependency 'git-pull-req', GitProc::Version::STRING
15
15
 
16
- gem.files = %w(README.md LICENSE CHANGELOG.md)
16
+ gem.files = %w(README.adoc LICENSE CHANGELOG.md)
17
17
  gem.files << 'man/git-process.1'
18
- gem.name = "git-process"
18
+ gem.name = 'git-process'
19
19
  gem.version = GitProc::Version::STRING
20
20
  gem.platform = Gem::Platform::RUBY
21
- gem.required_ruby_version = '>= 1.8.7'
21
+ gem.required_ruby_version = '>= 2.0'
22
22
  end
data/git-pull-req.gemspec CHANGED
@@ -1,20 +1,20 @@
1
1
  require File.expand_path('../lib/git-process/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ["Jim Moore"]
4
+ gem.authors = ['Jim Moore']
5
5
  gem.email = %w(moore.jim@gmail.com)
6
6
  gem.description = %q{Fetches the latest repository from the server, rebases/merges the current branch against the changes in the integration branch, then pushes the result up to a branch on the server of the same name. (Unless told not to.)}
7
7
  gem.summary = %q{Gets the latest changes that have happened on the integration branch, then pushes your changes to a feature branch on the server.}
8
- gem.homepage = "http://jdigger.github.com/git-process/"
9
- gem.license = 'ASL2'
8
+ gem.homepage = 'http://jdigger.github.com/git-process/'
9
+ gem.license = 'Apache-2.0'
10
10
 
11
- gem.add_dependency "git-process-lib", GitProc::Version::STRING
11
+ gem.add_dependency 'git-process-lib', GitProc::Version::STRING
12
12
 
13
- gem.files = %w(README.md LICENSE CHANGELOG.md bin/git-pull-req)
13
+ gem.files = %w(README.adoc LICENSE CHANGELOG.md bin/git-pull-req)
14
14
  gem.files << 'man/git-pull-req.1'
15
15
  gem.executables = ['git-pull-req']
16
- gem.name = "git-pull-req"
16
+ gem.name = 'git-pull-req'
17
17
  gem.version = GitProc::Version::STRING
18
18
  gem.platform = Gem::Platform::RUBY
19
- gem.required_ruby_version = '>= 1.8.7'
19
+ gem.required_ruby_version = '>= 2.0'
20
20
  end
data/git-sync.gemspec CHANGED
@@ -1,20 +1,20 @@
1
1
  require File.expand_path('../lib/git-process/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ["Jim Moore"]
4
+ gem.authors = ['Jim Moore']
5
5
  gem.email = %w(moore.jim@gmail.com)
6
6
  gem.description = %q{Fetches the latest repository from the server, rebases/merges the current branch against the changes in the integration branch, then pushes the result up to a branch on the server of the same name. (Unless told not to.)}
7
7
  gem.summary = %q{Gets the latest changes that have happened on the integration branch, then pushes your changes to a feature branch on the server.}
8
- gem.homepage = "http://jdigger.github.com/git-process/"
9
- gem.license = 'ASL2'
8
+ gem.homepage = 'http://jdigger.github.com/git-process/'
9
+ gem.license = 'Apache-2.0'
10
10
 
11
- gem.add_dependency "git-process-lib", GitProc::Version::STRING
11
+ gem.add_dependency 'git-process-lib', GitProc::Version::STRING
12
12
 
13
- gem.files = %w(README.md LICENSE CHANGELOG.md bin/git-sync)
13
+ gem.files = %w(README.adoc LICENSE CHANGELOG.md bin/git-sync)
14
14
  gem.files << 'man/git-sync.1'
15
15
  gem.executables = ['git-sync']
16
- gem.name = "git-sync"
16
+ gem.name = 'git-sync'
17
17
  gem.version = GitProc::Version::STRING
18
18
  gem.platform = Gem::Platform::RUBY
19
- gem.required_ruby_version = '>= 1.8.7'
19
+ gem.required_ruby_version = '>= 2.0'
20
20
  end
@@ -1,20 +1,20 @@
1
1
  require File.expand_path('../lib/git-process/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ["Jim Moore"]
4
+ gem.authors = ['Jim Moore']
5
5
  gem.email = %w(moore.jim@gmail.com)
6
6
  gem.description = %q{Fetches the latest repository from the server, rebases/merges the current branch against the changes in the integration branch, then pushes the result up to a branch on the server of the same name. (Unless told not to.)}
7
7
  gem.summary = %q{Gets the latest changes that have happened on the integration branch, then pushes your changes to a feature branch on the server.}
8
- gem.homepage = "http://jdigger.github.com/git-process/"
9
- gem.license = 'ASL2'
8
+ gem.homepage = 'http://jdigger.github.com/git-process/'
9
+ gem.license = 'Apache-2.0'
10
10
 
11
- gem.add_dependency "git-process-lib", GitProc::Version::STRING
11
+ gem.add_dependency 'git-process-lib', GitProc::Version::STRING
12
12
 
13
- gem.files = %w(README.md LICENSE CHANGELOG.md bin/git-to-master)
13
+ gem.files = %w(README.adoc LICENSE CHANGELOG.md bin/git-to-master)
14
14
  gem.files << 'man/git-to-master.1'
15
15
  gem.executables = ['git-to-master']
16
- gem.name = "git-to-master"
16
+ gem.name = 'git-to-master'
17
17
  gem.version = GitProc::Version::STRING
18
18
  gem.platform = Gem::Platform::RUBY
19
- gem.required_ruby_version = '>= 1.8.7'
19
+ gem.required_ruby_version = '>= 2.0'
20
20
  end
@@ -12,12 +12,23 @@
12
12
 
13
13
  module GitProc
14
14
 
15
+ #
16
+ # A Git Branch
17
+ #
18
+ # @attr_reader [String] name the name of the branch
19
+ #
15
20
  class GitBranch
16
21
  include Comparable
17
22
 
18
23
  attr_reader :name
19
24
 
20
25
 
26
+ # @param [String] name the name of the branch; if it starts with "remotes/" that part is stripped
27
+ # and {#remote?} will return {true}
28
+ # @param [Boolean] current is this the current branch?
29
+ # @param [GitLib] lib the {GitLib} to use for operations
30
+ #
31
+ # @todo instead of passing in _current_, detect it dynamically (e.g., look at HEAD)
21
32
  def initialize(name, current, lib)
22
33
  if /^remotes\// =~ name
23
34
  @name = name[8..-1]
@@ -31,47 +42,75 @@ module GitProc
31
42
  end
32
43
 
33
44
 
45
+ # @return [Boolean] is this the current branch?
34
46
  def current?
35
47
  @current
36
48
  end
37
49
 
38
50
 
51
+ # @return [Boolean] does this represent a remote branch?
39
52
  def remote?
40
53
  @remote
41
54
  end
42
55
 
43
56
 
57
+ # @return [Boolean] does this represent a local branch?
44
58
  def local?
45
59
  !@remote
46
60
  end
47
61
 
48
62
 
63
+ # @return [String] the name of the branch
49
64
  def to_s
50
65
  name
51
66
  end
52
67
 
53
68
 
69
+ # @return [GitLogger] the logger to use
54
70
  def logger
55
71
  @lib.logger
56
72
  end
57
73
 
58
74
 
75
+ # @return [String] the SHA-1 of the tip of this branch
59
76
  def sha
60
- @sha ||= @lib.sha(name)
77
+ @lib.sha(name)
61
78
  end
62
79
 
63
80
 
81
+ #
82
+ # Implements {Comparable} based on the branch name
83
+ #
84
+ # @param [String, #name] other the item to compare to this; if a {String} then it is compared to _self.name_,
85
+ # otherwise the names are compared
86
+ # @return [int, nil] -1, 0, 1 or nil per {Object#<=>}
64
87
  def <=>(other)
65
- self.name <=> other.name
88
+ if other.nil?
89
+ return nil
90
+ elsif other.is_a? String
91
+ return self.name <=> other
92
+ elsif other.respond_to? :name
93
+ return self.name <=> other.name
94
+ else
95
+ return nil
96
+ end
66
97
  end
67
98
 
68
99
 
100
+ # @param [String] base_branch_name the branch to compare to
101
+ # @return [Boolean] does this branch contain every commit in _base_branch_name_ as well as at least one more?
69
102
  def is_ahead_of(base_branch_name)
70
103
  contains_all_of(base_branch_name) and
71
104
  (@lib.rev_list(base_branch_name, @name, :oneline => true, :num_revs => 1) != '')
72
105
  end
73
106
 
74
107
 
108
+ #
109
+ # Delete this branch
110
+ #
111
+ # @param [Boolean] force should this force removal even if the branch has not been fully merged?
112
+ #
113
+ # @return [String] the output of running the git command
75
114
  def delete!(force = false)
76
115
  if local?
77
116
  @lib.branch(@name, :force => force, :delete => true)
@@ -63,7 +63,7 @@ module GitProc
63
63
 
64
64
 
65
65
  def include?(branch_name)
66
- @items.find { |b| b.name == branch_name } != nil
66
+ @items.any? { |b| b.name == branch_name }
67
67
  end
68
68
 
69
69
 
@@ -47,10 +47,12 @@ module GitProc
47
47
  end
48
48
 
49
49
 
50
+ # @param key [String] the key for the Git configuration, as would be passed to `git config --get`
51
+ # @return [String] the value of the configuration; nil if not found
50
52
  def [](key)
51
53
  value = config_hash[key]
52
54
  unless value
53
- value = @lib.command(:config, ['--get', key])
55
+ value = gitlib.command(:config, ['--get', key])
54
56
  value = nil if value.empty?
55
57
  config_hash[key] = value unless config_hash.empty?
56
58
  end
@@ -58,20 +60,27 @@ module GitProc
58
60
  end
59
61
 
60
62
 
63
+ # Sets to configuration value for this repository.
64
+ #
65
+ # @param key [String] the key for the Git configuration
66
+ # @param value [String] the value for the local configuration
67
+ #
68
+ # @return [String] the value
61
69
  def []=(key, value)
62
- @lib.command(:config, [key, value])
70
+ gitlib.command(:config, [key, value])
63
71
  config_hash[key] = value unless config_hash.empty?
64
72
  value
65
73
  end
66
74
 
67
75
 
68
76
  def set_global(key, value)
69
- @lib.command(:config, ['--global', key, value])
77
+ gitlib.command(:config, ['--global', key, value])
70
78
  config_hash[key] = value unless config_hash.empty?
71
79
  value
72
80
  end
73
81
 
74
82
 
83
+ # @return [GitLib] the GitLib this was initialized with
75
84
  def gitlib
76
85
  @lib
77
86
  end
@@ -82,8 +91,7 @@ module GitProc
82
91
  end
83
92
 
84
93
 
85
- #
86
- # @return true if no value has been set; the value of the config otherwise
94
+ # @return [Boolean] true if no value has been set; the value of the config otherwise
87
95
  def default_rebase_sync?
88
96
  val = self['gitProcess.defaultRebaseSync']
89
97
  val.nil? or val.to_boolean
@@ -104,18 +112,20 @@ module GitProc
104
112
  end
105
113
 
106
114
 
115
+ # @return [String] the name of the integration branch; defaults to 'master'
107
116
  def master_branch
108
117
  @master_branch ||= self['gitProcess.integrationBranch'] || 'master'
109
118
  end
110
119
 
111
120
 
121
+ # @deprecated use {GitProc::GitRemote#master_branch_name} instead
112
122
  def remote_master_branch
113
123
  remote.master_branch_name
114
124
  end
115
125
 
116
126
 
117
127
  def integration_branch
118
- remote.exists? ? remote_master_branch : self.master_branch
128
+ remote.exists? ? remote.master_branch_name : self.master_branch
119
129
  end
120
130
 
121
131
 
@@ -30,55 +30,77 @@ module GitProc
30
30
  #noinspection RubyTooManyMethodsInspection
31
31
  class GitLib
32
32
 
33
- # @param [Dir] dir
34
- def initialize(dir, opts)
35
- self.log_level = GitLib.log_level(opts)
33
+ # @param [Dir] dir the work dir
34
+ # @param [Hash] logging_opts see {log_level}
35
+ def initialize(dir, logging_opts)
36
+ self.log_level = GitLib.log_level(logging_opts)
36
37
  self.workdir = dir
37
38
  end
38
39
 
39
40
 
41
+ # @return [GitLogger] the logger to use
40
42
  def logger
41
43
  if @logger.nil?
42
44
  @logger = GitLogger.new(log_level)
43
45
  end
44
- @logger
46
+ return @logger
45
47
  end
46
48
 
47
49
 
50
+ #
51
+ # Decodes the [Hash] to determine what logging level to use
52
+ #
53
+ # @option opts [Fixnum] :log_level the log level from {Logger}
54
+ # @option opts :quiet {Logger::ERROR}
55
+ # @option opts :verbose {Logger::DEBUG}
56
+ #
57
+ # @return [Fixnum] the log level from Logger; defaults to {Logger::INFO}
58
+ #
48
59
  def self.log_level(opts)
49
60
  if opts[:log_level]
50
- opts[:log_level]
61
+ return opts[:log_level]
51
62
  elsif opts[:quiet]
52
- Logger::ERROR
63
+ return Logger::ERROR
53
64
  elsif opts[:verbose]
54
- Logger::DEBUG
65
+ return Logger::DEBUG
55
66
  else
56
- Logger::INFO
67
+ return Logger::INFO
57
68
  end
58
69
  end
59
70
 
60
71
 
72
+ # @return [Fixnum] the logging level to use; defaults to {Logger::WARN}
61
73
  def log_level
62
74
  @log_level || Logger::WARN
63
75
  end
64
76
 
65
77
 
78
+ # @param [Fixnum] lvl the logging level to use. See {Logger}
79
+ # @return [void]
66
80
  def log_level=(lvl)
67
81
  @log_level = lvl
68
82
  end
69
83
 
70
84
 
85
+ # @return [Dir] the working directory
71
86
  def workdir
72
87
  @workdir
73
88
  end
74
89
 
75
90
 
91
+ #
92
+ # Sets the working directory to use for the (non-bare) repository.
93
+ #
94
+ # If the directory is *not* part of an existing repository, a new repository is created. (i.e., "git init")
95
+ #
96
+ # @param [Dir] dir the working directory
97
+ # @return [void]
76
98
  def workdir=(dir)
77
99
  workdir = GitLib.find_workdir(dir)
78
100
  if workdir.nil?
79
101
  @workdir = dir
80
102
  logger.info { "Initializing new repository at #{dir}" }
81
- command(:init)
103
+ return command(:init)
82
104
  else
83
105
  @workdir = workdir
84
106
  logger.debug { "Opening existing repository at #{dir}" }
@@ -88,15 +110,16 @@ module GitProc
88
110
 
89
111
  def self.find_workdir(dir)
90
112
  if dir == File::SEPARATOR
91
- nil
113
+ return nil
92
114
  elsif File.directory?(File.join(dir, '.git'))
93
- dir
115
+ return dir
94
116
  else
95
- find_workdir(File.expand_path("#{dir}#{File::SEPARATOR}.."))
117
+ return find_workdir(File.expand_path("#{dir}#{File::SEPARATOR}.."))
96
118
  end
97
119
  end
98
120
 
99
121
 
122
+ # @return [void]
100
123
  def fetch_remote_changes(remote_name = nil)
101
124
  if remote.exists?
102
125
  fetch(remote_name || remote.name)
@@ -106,25 +129,37 @@ module GitProc
106
129
  end
107
130
 
108
131
 
132
+ #
133
+ # Executes a rebase, but translates any {GitExecuteError} to a {RebaseError}
134
+ #
135
+ # @param (see #rebase)
136
+ # @option (see #rebase)
137
+ # @raise [RebaseError] if there is a problem executing the rebase
109
138
  def proc_rebase(base, opts = {})
110
139
  begin
111
- rebase(base, opts)
140
+ return rebase(base, opts)
112
141
  rescue GitExecuteError => rebase_error
113
142
  raise RebaseError.new(rebase_error.message, self)
114
143
  end
115
144
  end
116
145
 
117
146
 
147
+ #
148
+ # Executes a merge, but translates any {GitExecuteError} to a {MergeError}
149
+ #
150
+ # @param (see #merge)
151
+ # @option (see #merge)
152
+ # @raise [MergeError] if there is a problem executing the merge
118
153
  def proc_merge(base, opts = {})
119
154
  begin
120
- merge(base, opts)
155
+ return merge(base, opts)
121
156
  rescue GitExecuteError => merge_error
122
157
  raise MergeError.new(merge_error.message, self)
123
158
  end
124
159
  end
125
160
 
126
161
 
127
- # @return [String] the previous remote sha ONLY IF it is not the same as the new remote sha; otherwise nil
162
+ # @return [String, nil] the previous remote sha ONLY IF it is not the same as the new remote sha; otherwise nil
128
163
  def previous_remote_sha(current_branch, remote_branch)
129
164
  return nil unless has_a_remote?
130
165
  return nil unless remote_branches.include?(remote_branch)
@@ -136,26 +171,38 @@ module GitProc
136
171
 
137
172
  if old_sha != new_sha
138
173
  logger.info('The remote branch has changed since the last time')
139
- old_sha
174
+ return old_sha
140
175
  else
141
176
  logger.debug 'The remote branch has not changed since the last time'
142
- nil
177
+ return nil
143
178
  end
144
179
  end
145
180
 
146
181
 
147
182
  def remote_branch_sha(remote_branch)
148
- logger.debug {"getting sha for remotes/#{remote_branch}"}
149
- rev_parse("remotes/#{remote_branch}") rescue ''
183
+ logger.debug { "getting sha for remotes/#{remote_branch}" }
184
+ return rev_parse("remotes/#{remote_branch}") rescue ''
150
185
  end
151
186
 
152
187
 
188
+ # @return [Boolean] is the current branch the "_parked_" branch?
153
189
  def is_parked?
154
190
  mybranches = self.branches()
155
- mybranches.parking == mybranches.current
191
+ return mybranches.parking == mybranches.current
156
192
  end
157
193
 
158
-
194
+ # Push the repository to the server.
195
+ #
196
+ # @param local_branch [String] the name of the local branch to push from
197
+ # @param remote_branch [String] the name of the remote branch to push to
198
+ #
199
+ # @option opts [Boolean] :local should this do nothing because it is in local-only mode?
200
+ # @option opts [Boolean] :force should it force the push even if it can not fast-forward?
201
+ # @option opts [Proc] :prepush a block to call before doing the push
202
+ # @option opts [Proc] :postpush a block to call after doing the push
203
+ #
204
+ # @return [void]
205
+ #
159
206
  def push_to_server(local_branch, remote_branch, opts = {})
160
207
  if opts[:local]
161
208
  logger.debug('Not pushing to the server because the user selected local-only.')
@@ -173,19 +220,21 @@ module GitProc
173
220
  end
174
221
 
175
222
 
223
+ # @return [GitConfig] the git configuration
176
224
  def config
177
225
  if @config.nil?
178
226
  @config = GitConfig.new(self)
179
227
  end
180
- @config
228
+ return @config
181
229
  end
182
230
 
183
231
 
232
+ # @return [GitRemote] the git remote configuration
184
233
  def remote
185
234
  if @remote.nil?
186
235
  @remote = GitProc::GitRemote.new(config)
187
236
  end
188
- @remote
237
+ return @remote
189
238
  end
190
239
 
191
240
 
@@ -195,18 +244,36 @@ module GitProc
195
244
  end
196
245
 
197
246
 
247
+ #
248
+ # `git add`
249
+ #
250
+ # @param [String] file the name of the file to add to the index
251
+ # @return [String] the output of 'git add'
198
252
  def add(file)
199
253
  logger.info { "Adding #{[*file].join(', ')}" }
200
- command(:add, ['--', file])
254
+ return command(:add, ['--', file])
201
255
  end
202
256
 
203
257
 
258
+ #
259
+ # `git commit`
260
+ #
261
+ # @param [String] msg the commit message
262
+ # @return [String] the output of 'git commit'
204
263
  def commit(msg = nil)
205
264
  logger.info 'Committing changes'
206
- command(:commit, msg.nil? ? nil : ['-m', msg])
265
+ return command(:commit, msg.nil? ? nil : ['-m', msg])
207
266
  end
208
267
 
209
268
 
269
+ #
270
+ # `git rebase`
271
+ #
272
+ # @param [String] upstream the commit-ish to rebase against
273
+ # @option opts :interactive do an interactive rebase
274
+ # @option opts [String] :oldbase the old base to rebase from
275
+ #
276
+ # @return [String] the output of 'git rebase'
210
277
  def rebase(upstream, opts = {})
211
278
  args = []
212
279
  if opts[:interactive]
@@ -220,42 +287,38 @@ module GitProc
220
287
  logger.info { "Rebasing #{branches.current.name} against #{upstream}" }
221
288
  args << upstream
222
289
  end
223
- command('rebase', args)
290
+ return command('rebase', args)
224
291
  end
225
292
 
226
293
 
294
+ #
295
+ # `git merge`
296
+ #
297
+ # @return [String] the output of 'git merge'
227
298
  def merge(base, opts= {})
228
299
  logger.info { "Merging #{branches.current.name} with #{base}" }
229
300
  args = []
230
301
  args << '-s' << opts[:merge_strategy] if opts[:merge_strategy]
231
302
  args << base
232
- command(:merge, args)
303
+ return command(:merge, args)
233
304
  end
234
305
 
235
306
 
307
+ #
308
+ # `git fetch`
309
+ #
310
+ # @return [String] the output of 'git fetch'
236
311
  def fetch(name = remote.name)
237
312
  logger.info 'Fetching the latest changes from the server'
238
313
  output = self.command(:fetch, ['-p', name])
239
314
 
240
315
  log_fetch_changes(fetch_changes(output))
241
316
 
242
- output
243
- end
244
-
245
-
246
- # @param [Hash] changes a hash of the changes that were made
247
- #
248
- # @return [void]
249
- def log_fetch_changes(changes)
250
- changes.each do |key, v|
251
- unless v.empty?
252
- logger.info { " #{key.to_s.sub(/_/, ' ')}: #{v.join(', ')}" }
253
- end
254
- end
317
+ return output
255
318
  end
256
319
 
257
320
 
258
- # @return [Hash]
321
+ # @return [Hash] with lists for each of :new_branch, :new_tag, :force_updated, :deleted, :updated
259
322
  def fetch_changes(output)
260
323
  changed = output.split("\n")
261
324
 
@@ -290,11 +353,13 @@ module GitProc
290
353
  end
291
354
 
292
355
 
356
+ # @return [GitBranches]
293
357
  def branches
294
358
  GitProc::GitBranches.new(self)
295
359
  end
296
360
 
297
361
 
362
+ # @return [GitBranches]
298
363
  def remote_branches
299
364
  GitProc::GitBranches.new(self, :remote => true)
300
365
  end
@@ -311,26 +376,28 @@ module GitProc
311
376
  # @option opts [Boolean] :no_color force not using any ANSI color codes
312
377
  # @option opts [String] :rename the new name for the branch
313
378
  # @option opts [String] :upstream the new branch to track
314
- # @option opts [String] :base_branch the branch to base the new branch off of;
315
- # defaults to 'master'
379
+ # @option opts [String] :base_branch ('master') the branch to base the new branch off of
316
380
  #
317
381
  # @return [String] the output of running the git command
318
382
  def branch(branch_name, opts = {})
319
- if opts[:delete]
320
- delete_branch(branch_name, opts[:force])
321
- elsif opts[:rename]
322
- rename_branch(branch_name, opts[:rename])
323
- elsif opts[:upstream]
324
- set_upstream_branch(branch_name, opts[:upstream])
325
- elsif branch_name
326
- if opts[:force]
327
- change_branch(branch_name, opts[:base_branch])
383
+ if branch_name
384
+ if opts[:delete]
385
+ return delete_branch(branch_name, opts[:force])
386
+ elsif opts[:rename]
387
+ return rename_branch(branch_name, opts[:rename])
388
+ elsif opts[:upstream]
389
+ return set_upstream_branch(branch_name, opts[:upstream])
328
390
  else
329
- create_branch(branch_name, opts[:base_branch])
391
+ base_branch = opts[:base_branch] || 'master'
392
+ if opts[:force]
393
+ return change_branch(branch_name, base_branch)
394
+ else
395
+ return create_branch(branch_name, base_branch)
396
+ end
330
397
  end
331
398
  else
332
399
  #list_branches(opts)
333
- list_branches(opts[:all], opts[:remote], opts[:no_color])
400
+ return list_branches(opts[:all], opts[:remote], opts[:no_color])
334
401
  end
335
402
  end
336
403
 
@@ -343,68 +410,120 @@ module GitProc
343
410
  # @param [String] remote_branch the name of the branch to push to; nil -> same as local_branch
344
411
  #
345
412
  # @option opts [Boolean, String] :delete delete the remote branch
346
- # @option opts [Boolean] :force force the update, even if not a fast-forward
413
+ # @option opts [Boolean] :force force the update, even if not a fast-forward?
347
414
  #
348
- # @return [void]
415
+ # @return [String] the output of the push command
349
416
  #
350
417
  # @raise [ArgumentError] if :delete is true, but no branch name is given
418
+ #
351
419
  def push(remote_name, local_branch, remote_branch, opts = {})
420
+ if opts[:delete]
421
+ return push_delete(remote_branch || local_branch, remote_name, opts)
422
+ else
423
+ return push_to_remote(local_branch, remote_branch, remote_name, opts)
424
+ end
425
+ end
426
+
427
+
428
+ #
429
+ # Pushes the given branch to the server.
430
+ #
431
+ # @param [String] remote_name the repository name; nil -> 'origin'
432
+ # @param [String] local_branch the local branch to push; nil -> the current branch
433
+ # @param [String] remote_branch the name of the branch to push to; nil -> same as local_branch
434
+ #
435
+ # @option opts [Boolean] :force force the update, even if not a fast-forward?
436
+ #
437
+ # @return [String] the output of the push command
438
+ #
439
+ def push_to_remote(local_branch, remote_branch, remote_name, opts)
352
440
  remote_name ||= 'origin'
353
441
 
354
442
  args = [remote_name]
355
443
 
356
- if opts[:delete]
357
- if remote_branch
358
- rb = remote_branch
359
- elsif local_branch
360
- rb = local_branch
361
- elsif !(opts[:delete].is_a? TrueClass)
362
- rb = opts[:delete]
444
+ local_branch ||= branches.current
445
+ remote_branch ||= local_branch
446
+ args << '-f' if opts[:force]
447
+
448
+ logger.info do
449
+ if local_branch == remote_branch
450
+ "Pushing to '#{remote_branch}' on '#{remote_name}'."
363
451
  else
364
- raise ArgumentError.new('Need a branch name to delete.')
452
+ "Pushing #{local_branch} to '#{remote_branch}' on '#{remote_name}'."
365
453
  end
454
+ end
366
455
 
367
- int_branch = config.master_branch
368
- if rb == int_branch
369
- raise GitProc::GitProcessError.new("Can not delete the integration branch '#{int_branch}'")
370
- end
456
+ args << "#{local_branch}:#{remote_branch}"
457
+ return command(:push, args)
458
+ end
371
459
 
372
- logger.info { "Deleting remote branch '#{rb}' on '#{remote_name}'." }
373
- args << '--delete' << rb
374
- else
375
- local_branch ||= branches.current
376
- remote_branch ||= local_branch
377
- args << '-f' if opts[:force]
378
460
 
379
- logger.info do
380
- if local_branch == remote_branch
381
- "Pushing to '#{remote_branch}' on '#{remote_name}'."
382
- else
383
- "Pushing #{local_branch} to '#{remote_branch}' on '#{remote_name}'."
384
- end
385
- end
461
+ #
462
+ # Pushes the given branch to the server.
463
+ #
464
+ # @param [String] remote_name the repository name; nil -> 'origin'
465
+ # @param [String] branch_name the name of the branch to push to
466
+ #
467
+ # @option opts [Boolean, String] :delete if a String it is the branch name
468
+ #
469
+ # @return [String] the output of the push command
470
+ #
471
+ # @raise [ArgumentError] no branch name is given
472
+ # @raise [raise GitProc::GitProcessError] trying to delete the integration branch
473
+ #
474
+ # @todo remove the opts param
475
+ #
476
+ def push_delete(branch_name, remote_name, opts)
477
+ remote_name ||= 'origin'
478
+
479
+ args = [remote_name]
386
480
 
387
- args << "#{local_branch}:#{remote_branch}"
481
+ if branch_name
482
+ rb = branch_name
483
+ elsif !(opts[:delete].is_a? TrueClass)
484
+ rb = opts[:delete]
485
+ else
486
+ raise ArgumentError.new('Need a branch name to delete.')
388
487
  end
389
- command(:push, args)
488
+
489
+ int_branch = config.master_branch
490
+ if rb == int_branch
491
+ raise GitProc::GitProcessError.new("Can not delete the integration branch '#{int_branch}'")
492
+ end
493
+
494
+ logger.info { "Deleting remote branch '#{rb}' on '#{remote_name}'." }
495
+ args << '--delete' << rb
496
+ return command(:push, args)
390
497
  end
391
498
 
392
499
 
500
+ # `git rebase --continue`
501
+ #
502
+ # @return [String] the output of the git command
393
503
  def rebase_continue
394
504
  command(:rebase, '--continue')
395
505
  end
396
506
 
397
507
 
508
+ # `git stash --save`
509
+ #
510
+ # @return [String] the output of the git command
398
511
  def stash_save
399
512
  command(:stash, %w(save))
400
513
  end
401
514
 
402
515
 
516
+ # `git stash --pop`
517
+ #
518
+ # @return [String] the output of the git command
403
519
  def stash_pop
404
520
  command(:stash, %w(pop))
405
521
  end
406
522
 
407
523
 
524
+ # `git show`
525
+ #
526
+ # @return [String] the output of the git command
408
527
  def show(refspec)
409
528
  command(:show, refspec)
410
529
  end
@@ -436,11 +555,19 @@ module GitProc
436
555
  end
437
556
 
438
557
 
558
+ # @return [int] the number of commits that exist in the current branch
439
559
  def log_count
440
560
  command(:log, '--oneline').split(/\n/).length
441
561
  end
442
562
 
443
563
 
564
+ # Remove the files from the Index
565
+ #
566
+ # @param [Array<String>] files the file names to remove from the Index
567
+ #
568
+ # @option opts :force if exists and not false, will force the removal of the files
569
+ #
570
+ # @return [String] the output of the git command
444
571
  def remove(files, opts = {})
445
572
  args = []
446
573
  args << '-f' if opts[:force]
@@ -464,6 +591,13 @@ module GitProc
464
591
  end
465
592
 
466
593
 
594
+ #
595
+ # Resets the Index/Working Directory to the given revision
596
+ #
597
+ # @param [String] rev_name the revision name (commit-ish) to go back to
598
+ #
599
+ # @option opts :hard should the working directory be changed? If {false} or missing, will only update the Index
600
+ #
467
601
  def reset(rev_name, opts = {})
468
602
  args = []
469
603
  args << '--hard' if opts[:hard]
@@ -484,15 +618,31 @@ module GitProc
484
618
  end
485
619
 
486
620
 
621
+ #
622
+ # Translate the commit-ish name to the SHA-1 hash value
623
+ #
624
+ # @return [String, nil] the SHA-1 value, or nil if the revision name is unknown
625
+ #
487
626
  def rev_parse(name)
488
- command('rev-parse', name)
627
+ sha = command('rev-parse', ['--revs-only', name])
628
+ return sha.empty? ? nil : sha
489
629
  end
490
630
 
491
631
 
492
- alias sha rev_parse
632
+ alias :sha :rev_parse
493
633
 
494
634
 
495
- # @return [String]
635
+ #
636
+ # Executes the given git command
637
+ #
638
+ # @param [Symbol, String] cmd the command to run (e.g., :commit)
639
+ # @param [Array<String, Symbol>] opts the arguments to pass to the command
640
+ # @param [Boolean] chdir should the shell change to the top of the working dir before executing the command?
641
+ # @param [String] redirect ???????
642
+ # @yield the block to run in the context of running the command
643
+ #
644
+ # @return [String] the output of the git command
645
+ #
496
646
  def command(cmd, opts = [], chdir = true, redirect = '', &block)
497
647
  ENV['GIT_INDEX_FILE'] = File.join(workdir, '.git', 'index')
498
648
  ENV['GIT_DIR'] = File.join(workdir, '.git')
@@ -512,6 +662,11 @@ module GitProc
512
662
  end
513
663
 
514
664
 
665
+ #
666
+ # Writes the current SHA-1 for the tip of the branch to the "sync control file"
667
+ #
668
+ # @return [void]
669
+ # @see GitLib#read_sync_control_file
515
670
  def write_sync_control_file(branch_name)
516
671
  latest_sha = rev_parse(branch_name)
517
672
  filename = sync_control_filename(branch_name)
@@ -520,6 +675,8 @@ module GitProc
520
675
  end
521
676
 
522
677
 
678
+ # @return [String, nil] the SHA-1 of the latest sync performed for the branch, or nil if none is recorded
679
+ # @see GitLib#write_sync_control_file
523
680
  def read_sync_control_file(branch_name)
524
681
  filename = sync_control_filename(branch_name)
525
682
  if File.exists?(filename)
@@ -535,10 +692,16 @@ module GitProc
535
692
  end
536
693
 
537
694
 
695
+ #
696
+ # Delete the sync control file for the branch
697
+ #
698
+ # @return [void]
699
+ # @see GitLib#write_sync_control_file
538
700
  def delete_sync_control_file!(branch_name)
539
701
  filename = sync_control_filename(branch_name)
540
702
  logger.debug { "Deleting sync control file, #{filename}" }
541
703
 
704
+ # on some systems, especially Windows, the file may be locked. wait for it to unlock
542
705
  counter = 10
543
706
  while counter > 0
544
707
  begin
@@ -552,6 +715,8 @@ module GitProc
552
715
  end
553
716
 
554
717
 
718
+ # @return [Boolean] does the sync control file exist?
719
+ # @see GitLib#write_sync_control_file
555
720
  def sync_control_file_exists?(branch_name)
556
721
  filename = sync_control_filename(branch_name)
557
722
  File.exist?(filename)
@@ -584,12 +749,31 @@ module GitProc
584
749
  private
585
750
 
586
751
 
752
+ #
753
+ # Create the CLI for the git command
754
+ #
755
+ # @param [Symbol, String] cmd the command to run (e.g., :commit)
756
+ # @param [Array<String, Symbol>] opts the arguments to pass to the command
757
+ # @param [String] redirect ???????
758
+ #
759
+ # @return [String] the command line to run
760
+ #
587
761
  def create_git_command(cmd, opts, redirect)
588
762
  opts = [opts].flatten.map { |s| escape(s) }.join(' ')
589
- "git #{cmd} #{opts} #{redirect} 2>&1"
763
+ return "git #{cmd} #{opts} #{redirect} 2>&1"
590
764
  end
591
765
 
592
766
 
767
+ #
768
+ # Executes the given git command
769
+ #
770
+ # @param [String] path the directory to run the command in
771
+ # @param [String] git_cmd the CLI command to execute
772
+ # @param [Boolean] chdir should the shell change to the top of the working dir before executing the command?
773
+ # @param [Proc] block the block to run in the context of running the command
774
+ #
775
+ # @return [String] the output of the git command
776
+ #
593
777
  def command_git_cmd(path, git_cmd, chdir, block)
594
778
  out = nil
595
779
  if chdir and (Dir.getwd != path)
@@ -597,7 +781,7 @@ module GitProc
597
781
  else
598
782
  out = run_command(git_cmd, &block)
599
783
  end
600
- out
784
+ return out
601
785
  end
602
786
 
603
787
 
@@ -608,25 +792,35 @@ module GitProc
608
792
  raise GitProc::GitExecuteError.new(git_cmd + ':' + out.to_s)
609
793
  end
610
794
  end
611
- out
795
+ return out
612
796
  end
613
797
 
614
798
 
799
+ #
800
+ # Executes the given git command
801
+ #
802
+ # @param [String] git_cmd the CLI command to execute
803
+ # @yield the block to run in the context of running the command. See {IO#popen}
804
+ #
805
+ # @return [String] the output of the git command
806
+ #
615
807
  def run_command(git_cmd, &block)
616
808
  if block_given?
617
- IO.popen(git_cmd, &block)
809
+ return IO.popen(git_cmd, &block)
618
810
  else
619
- `#{git_cmd}`.chomp
811
+ return `#{git_cmd}`.chomp
620
812
  end
621
813
  end
622
814
 
623
815
 
816
+ # @return [String]
624
817
  def escape(s)
625
818
  escaped = s.to_s.gsub('\'', '\'\\\'\'')
626
819
  %Q{"#{escaped}"}
627
820
  end
628
821
 
629
822
 
823
+ # @return [String]
630
824
  def change_branch(branch_name, base_branch)
631
825
  raise ArgumentError.new('Need :base_branch when using :force for a branch.') unless base_branch
632
826
  logger.info { "Changing branch '#{branch_name}' to point to '#{base_branch}'." }
@@ -635,6 +829,7 @@ module GitProc
635
829
  end
636
830
 
637
831
 
832
+ # @return [String]
638
833
  def create_branch(branch_name, base_branch)
639
834
  logger.info { "Creating new branch '#{branch_name}' based on '#{base_branch}'." }
640
835
 
@@ -642,6 +837,7 @@ module GitProc
642
837
  end
643
838
 
644
839
 
840
+ # @return [String]
645
841
  def list_branches(all_branches, remote_branches, no_color)
646
842
  args = []
647
843
  args << '-a' if all_branches
@@ -651,6 +847,7 @@ module GitProc
651
847
  end
652
848
 
653
849
 
850
+ # @return [String]
654
851
  def delete_branch(branch_name, force)
655
852
  logger.info { "Deleting local branch '#{branch_name}'." } unless branch_name == '_parking_'
656
853
 
@@ -658,6 +855,7 @@ module GitProc
658
855
  end
659
856
 
660
857
 
858
+ # @return [String]
661
859
  def rename_branch(branch_name, new_name)
662
860
  logger.info { "Renaming branch '#{branch_name}' to '#{new_name}'." }
663
861
 
@@ -665,8 +863,23 @@ module GitProc
665
863
  end
666
864
 
667
865
 
866
+ # @return [String]
668
867
  def sync_control_filename(branch_name)
669
- File.join(File.join(workdir, '.git'), "gitprocess-sync-#{remote.name}--#{branch_name}")
868
+ normalized_branch_name = branch_name.to_s.gsub(/[\/]/, "-")
869
+
870
+ return File.join(File.join(workdir, '.git'), "gitprocess-sync-#{remote.name}--#{normalized_branch_name}")
871
+ end
872
+
873
+
874
+ # @param [Hash] changes a hash of the changes that were made
875
+ #
876
+ # @return [void]
877
+ def log_fetch_changes(changes)
878
+ changes.each do |key, v|
879
+ unless v.empty?
880
+ logger.info { " #{key.to_s.sub(/_/, ' ')}: #{v.join(', ')}" }
881
+ end
882
+ end
670
883
  end
671
884
 
672
885
  end