git-process-lib 2.0.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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