git-process 1.0.11 → 1.1.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/CHANGELOG.md +37 -9
- data/Gemfile +2 -2
- data/Gemfile.lock +17 -17
- data/README.md +14 -7
- data/bin/git-new-fb +10 -2
- data/bin/git-pull-request +30 -6
- data/bin/git-sync +5 -2
- data/bin/git-to-master +62 -11
- data/git-process.gemspec +15 -15
- data/lib/git-process/abstract_error_builder.rb +0 -3
- data/lib/git-process/changed_file_helper.rb +30 -24
- data/lib/git-process/git_abstract_merge_error_builder.rb +31 -11
- data/lib/git-process/git_branch.rb +5 -0
- data/lib/git-process/git_config.rb +153 -0
- data/lib/git-process/git_lib.rb +212 -164
- data/lib/git-process/git_logger.rb +84 -0
- data/lib/git-process/git_merge_error.rb +3 -14
- data/lib/git-process/git_process.rb +44 -73
- data/lib/git-process/git_process_options.rb +6 -6
- data/lib/git-process/git_rebase_error.rb +4 -13
- data/lib/git-process/git_remote.rb +254 -0
- data/lib/git-process/github_configuration.rb +298 -0
- data/lib/git-process/github_pull_request.rb +65 -27
- data/lib/git-process/new_fb.rb +14 -4
- data/lib/git-process/parked_changes_error.rb +1 -1
- data/lib/git-process/pull_request.rb +100 -13
- data/lib/git-process/pull_request_error.rb +25 -0
- data/lib/git-process/rebase_to_master.rb +47 -27
- data/lib/git-process/sync.rb +48 -33
- data/lib/git-process/uncommitted_changes_error.rb +1 -1
- data/lib/git-process/version.rb +2 -2
- data/spec/GitRepoHelper.rb +48 -25
- data/spec/changed_file_helper_spec.rb +39 -58
- data/spec/git_abstract_merge_error_builder_spec.rb +42 -33
- data/spec/git_branch_spec.rb +30 -30
- data/spec/git_config_spec.rb +45 -0
- data/spec/git_lib_spec.rb +103 -122
- data/spec/git_logger_spec.rb +66 -0
- data/spec/git_process_spec.rb +81 -81
- data/spec/git_remote_spec.rb +188 -0
- data/spec/git_status_spec.rb +36 -36
- data/spec/github_configuration_spec.rb +152 -0
- data/spec/github_pull_request_spec.rb +39 -35
- data/spec/github_test_helper.rb +49 -0
- data/spec/new_fb_spec.rb +65 -24
- data/spec/pull_request_helper.rb +94 -0
- data/spec/pull_request_spec.rb +128 -0
- data/spec/rebase_to_master_spec.rb +241 -145
- data/spec/spec_helper.rb +20 -0
- data/spec/sync_spec.rb +115 -109
- metadata +34 -20
- data/lib/git-process/github_client.rb +0 -83
- data/lib/git-process/github_service.rb +0 -174
- data/spec/github_service_spec.rb +0 -211
@@ -19,32 +19,34 @@ module GitProc
|
|
19
19
|
#
|
20
20
|
# Provides support for prompting the user when the dir/index is dirty.
|
21
21
|
#
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
#noinspection RubyControlFlowConversionInspection,RubyClassMethodNamingConvention,RubyInstanceMethodNamingConvention
|
23
|
+
class ChangeFileHelper
|
24
|
+
|
25
|
+
# @param [GitLib] gitlib
|
26
|
+
def initialize(gitlib)
|
27
|
+
@gitlib = gitlib
|
28
|
+
end
|
28
29
|
|
29
30
|
|
30
31
|
def offer_to_help_uncommitted_changes
|
31
|
-
stat = status
|
32
|
+
stat = gitlib.status
|
32
33
|
|
33
34
|
if stat.unmerged.empty?
|
34
35
|
handle_unknown_files(stat)
|
35
|
-
handle_changed_files(status) # refresh status in case it changed earlier
|
36
|
+
handle_changed_files(gitlib.status) # refresh status in case it changed earlier
|
36
37
|
else
|
37
|
-
logger.info { "Can not offer to auto-add unmerged files: #{stat.unmerged.inspect}" }
|
38
|
+
gitlib.logger.info { "Can not offer to auto-add unmerged files: #{stat.unmerged.inspect}" }
|
38
39
|
raise UncommittedChangesError.new
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
43
|
|
44
|
+
#noinspection RubyControlFlowConversionInspection
|
43
45
|
def handle_unknown_files(stat)
|
44
46
|
if not stat.unknown.empty?
|
45
|
-
resp = ask_how_to_handle_unknown_files(stat)
|
47
|
+
resp = ChangeFileHelper.ask_how_to_handle_unknown_files(stat)
|
46
48
|
if resp == :add
|
47
|
-
add(stat.unknown)
|
49
|
+
gitlib.add(stat.unknown)
|
48
50
|
end
|
49
51
|
end
|
50
52
|
end
|
@@ -52,26 +54,25 @@ module GitProc
|
|
52
54
|
|
53
55
|
def handle_changed_files(stat)
|
54
56
|
if not stat.modified.empty? or not stat.added.empty? or not stat.deleted.empty?
|
55
|
-
resp = ask_how_to_handle_changed_files(stat)
|
57
|
+
resp = ChangeFileHelper.ask_how_to_handle_changed_files(stat)
|
56
58
|
if resp == :commit
|
57
59
|
changed_files = (stat.added + stat.modified - stat.deleted).sort.uniq
|
58
60
|
|
59
|
-
add(changed_files) unless changed_files.empty?
|
60
|
-
remove(stat.deleted) unless stat.deleted.empty?
|
61
|
+
gitlib.add(changed_files) unless changed_files.empty?
|
62
|
+
gitlib.remove(stat.deleted) unless stat.deleted.empty?
|
61
63
|
|
62
|
-
commit(nil)
|
64
|
+
gitlib.commit(nil)
|
63
65
|
else
|
64
|
-
stash_save
|
65
|
-
@stash_pushed = true
|
66
|
+
gitlib.stash_save
|
66
67
|
end
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
70
71
|
|
71
|
-
def ask_how_to_handle_unknown_files(stat)
|
72
|
+
def self.ask_how_to_handle_unknown_files(stat)
|
72
73
|
show_changes(:unknown, stat)
|
73
|
-
resp = ask(
|
74
|
-
q.responses[:not_valid] =
|
74
|
+
resp = ask('Would you like to (a)dd them or (i)gnore them? ') do |q|
|
75
|
+
q.responses[:not_valid] = 'Please respond with either (a)dd or (i)gnore. (Ctl-C to abort.) '
|
75
76
|
q.case = :down
|
76
77
|
q.validate = /a|i/i
|
77
78
|
end
|
@@ -80,7 +81,7 @@ module GitProc
|
|
80
81
|
end
|
81
82
|
|
82
83
|
|
83
|
-
def show_changes(type, stat)
|
84
|
+
def self.show_changes(type, stat)
|
84
85
|
files = stat.send(type)
|
85
86
|
|
86
87
|
if type != :deleted
|
@@ -93,10 +94,10 @@ module GitProc
|
|
93
94
|
end
|
94
95
|
|
95
96
|
|
96
|
-
def ask_how_to_handle_changed_files(stat)
|
97
|
+
def self.ask_how_to_handle_changed_files(stat)
|
97
98
|
[:added, :modified, :deleted].each { |t| show_changes(t, stat) }
|
98
|
-
resp = ask(
|
99
|
-
q.responses[:not_valid] =
|
99
|
+
resp = ask('Would you like to (c)ommit them or (s)tash them? ') do |q|
|
100
|
+
q.responses[:not_valid] = 'Please respond with either (c)ommit or (s)tash. (Ctl-C to abort.) '
|
100
101
|
q.case = :down
|
101
102
|
q.validate = /c|s/i
|
102
103
|
end
|
@@ -104,6 +105,11 @@ module GitProc
|
|
104
105
|
resp == 'c' ? :commit : :stash
|
105
106
|
end
|
106
107
|
|
108
|
+
|
109
|
+
def gitlib
|
110
|
+
@gitlib
|
111
|
+
end
|
112
|
+
|
107
113
|
end
|
108
114
|
|
109
115
|
end
|
@@ -15,12 +15,19 @@ require 'shellwords'
|
|
15
15
|
|
16
16
|
module GitProc
|
17
17
|
|
18
|
-
#
|
19
|
-
|
20
|
-
#
|
21
|
-
module AbstractMergeErrorBuilder
|
18
|
+
#noinspection RubyTooManyInstanceVariablesInspection
|
19
|
+
class AbstractMergeErrorBuilder
|
22
20
|
include GitProc::AbstractErrorBuilder
|
23
21
|
|
22
|
+
attr_reader :gitlib, :error_message, :continue_command
|
23
|
+
|
24
|
+
|
25
|
+
def initialize(gitlib, error_message, continue_command)
|
26
|
+
@gitlib = gitlib
|
27
|
+
@error_message = error_message
|
28
|
+
@continue_command = continue_command
|
29
|
+
end
|
30
|
+
|
24
31
|
|
25
32
|
def resolved_files
|
26
33
|
@resolved_files ||= find_resolved_files
|
@@ -53,7 +60,7 @@ module GitProc
|
|
53
60
|
end
|
54
61
|
end
|
55
62
|
|
56
|
-
unless
|
63
|
+
unless config.rerere_enabled?
|
57
64
|
msg << "\n\nConsider turning on 'rerere'.\nSee http://git-scm.com/2010/03/08/rerere.html for more information."
|
58
65
|
end
|
59
66
|
|
@@ -70,13 +77,13 @@ module GitProc
|
|
70
77
|
def build_commands
|
71
78
|
commands = []
|
72
79
|
|
73
|
-
commands << 'git config --global rerere.enabled true' unless
|
80
|
+
commands << 'git config --global rerere.enabled true' unless config.rerere_enabled?
|
74
81
|
|
75
82
|
resolved_files.each do |file|
|
76
83
|
commands << "# Verify that 'rerere' did the right thing for '#{file}'."
|
77
84
|
end
|
78
85
|
|
79
|
-
unless resolved_files.empty? or
|
86
|
+
unless resolved_files.empty? or config.rerere_autoupdate?
|
80
87
|
escaped_files = shell_escaped_files(resolved_files)
|
81
88
|
commands << "git add #{escaped_files}"
|
82
89
|
end
|
@@ -103,22 +110,35 @@ module GitProc
|
|
103
110
|
|
104
111
|
|
105
112
|
def unmerged
|
106
|
-
@unmerged ||=
|
113
|
+
@unmerged ||= status.unmerged
|
107
114
|
end
|
108
115
|
|
109
116
|
|
110
117
|
def added
|
111
|
-
@added ||=
|
118
|
+
@added ||= status.added
|
112
119
|
end
|
113
120
|
|
114
121
|
|
115
122
|
def deleted
|
116
|
-
@deleted ||=
|
123
|
+
@deleted ||= status.deleted
|
117
124
|
end
|
118
125
|
|
119
126
|
|
120
127
|
def modified
|
121
|
-
@modified ||=
|
128
|
+
@modified ||= status.modified
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
|
135
|
+
def config
|
136
|
+
gitlib.config
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
def status
|
141
|
+
@status ||= gitlib.status
|
122
142
|
end
|
123
143
|
|
124
144
|
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
2
|
+
# you may not use this file except in compliance with the License.
|
3
|
+
# You may obtain a copy of the License at
|
4
|
+
#
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
#
|
7
|
+
# Unless required by applicable law or agreed to in writing, software
|
8
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
9
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the License for the specific language governing permissions and
|
11
|
+
# limitations under the License.
|
12
|
+
|
13
|
+
require 'git-process/git_logger'
|
14
|
+
require 'git-process/git_branch'
|
15
|
+
require 'git-process/git_branches'
|
16
|
+
require 'git-process/git_status'
|
17
|
+
require 'git-process/git_process_error'
|
18
|
+
|
19
|
+
|
20
|
+
class String
|
21
|
+
|
22
|
+
def to_boolean
|
23
|
+
return false if self == false || self.nil? || self =~ (/(false|f|no|n|0)$/i)
|
24
|
+
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
25
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
class NilClass
|
32
|
+
def to_boolean
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
module GitProc
|
39
|
+
|
40
|
+
#
|
41
|
+
# Provides Git configuration
|
42
|
+
#
|
43
|
+
class GitConfig
|
44
|
+
|
45
|
+
def initialize(lib)
|
46
|
+
@lib = lib
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def [](key)
|
51
|
+
value = config_hash[key]
|
52
|
+
unless value
|
53
|
+
value = @lib.command(:config, ['--get', key])
|
54
|
+
value = nil if value.empty?
|
55
|
+
config_hash[key] = value unless config_hash.empty?
|
56
|
+
end
|
57
|
+
value
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def []=(key, value)
|
62
|
+
@lib.command(:config, [key, value])
|
63
|
+
config_hash[key] = value unless config_hash.empty?
|
64
|
+
value
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def set_global(key, value)
|
69
|
+
@lib.command(:config, ['--global', key, value])
|
70
|
+
config_hash[key] = value unless config_hash.empty?
|
71
|
+
value
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def gitlib
|
76
|
+
@lib
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def logger
|
81
|
+
gitlib.logger
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def master_branch
|
86
|
+
@master_branch ||= self['gitProcess.integrationBranch'] || 'master'
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def remote_master_branch
|
91
|
+
remote.master_branch_name
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def integration_branch
|
96
|
+
remote.exists? ? remote_master_branch : self.master_branch
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def rerere_enabled?
|
101
|
+
re = self['rerere.enabled']
|
102
|
+
re && re.to_boolean
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
def rerere_enabled(re, global = true)
|
107
|
+
if global
|
108
|
+
set_global('rerere.enabled', re)
|
109
|
+
else
|
110
|
+
self['rerere.enabled'] = re
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def rerere_enabled=(re)
|
116
|
+
rerere_enabled(re, false)
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def rerere_autoupdate?
|
121
|
+
re = self['rerere.autoupdate']
|
122
|
+
re && re.to_boolean
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
def rerere_autoupdate(re, global = true)
|
127
|
+
if global
|
128
|
+
set_global('rerere.autoupdate', re)
|
129
|
+
else
|
130
|
+
self['rerere.autoupdate'] = re
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def rerere_autoupdate=(re)
|
136
|
+
rerere_autoupdate(re, false)
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def remote
|
143
|
+
gitlib.remote
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def config_hash
|
148
|
+
@config_hash ||= {}
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
data/lib/git-process/git_lib.rb
CHANGED
@@ -13,28 +13,11 @@
|
|
13
13
|
require 'logger'
|
14
14
|
require 'git-process/git_branch'
|
15
15
|
require 'git-process/git_branches'
|
16
|
+
require 'git-process/git_remote'
|
16
17
|
require 'git-process/git_status'
|
17
18
|
require 'git-process/git_process_error'
|
18
19
|
|
19
20
|
|
20
|
-
class String
|
21
|
-
|
22
|
-
def to_boolean
|
23
|
-
return false if self == false || self.nil? || self =~ (/(false|f|no|n|0)$/i)
|
24
|
-
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
25
|
-
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
class NilClass
|
32
|
-
def to_boolean
|
33
|
-
false
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
21
|
module GitProc
|
39
22
|
|
40
23
|
class GitExecuteError < GitProcessError
|
@@ -44,41 +27,95 @@ module GitProc
|
|
44
27
|
#
|
45
28
|
# Provides Git commands
|
46
29
|
#
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
30
|
+
#noinspection RubyTooManyMethodsInspection
|
31
|
+
class GitLib
|
32
|
+
|
33
|
+
# @param [Dir] dir
|
34
|
+
def initialize(dir, opts)
|
35
|
+
self.log_level = GitLib.log_level(opts)
|
36
|
+
self.workdir = dir
|
37
|
+
end
|
38
|
+
|
52
39
|
|
53
40
|
def logger
|
54
41
|
if @logger.nil?
|
55
|
-
@logger =
|
56
|
-
@logger.level = log_level || Logger::WARN
|
57
|
-
@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
58
|
-
@logger.formatter = proc do |_, _, _, msg|
|
59
|
-
"#{msg}\n"
|
60
|
-
end
|
42
|
+
@logger = GitLogger.new(log_level)
|
61
43
|
end
|
62
44
|
@logger
|
63
45
|
end
|
64
46
|
|
65
47
|
|
66
|
-
def
|
67
|
-
|
48
|
+
def self.log_level(opts)
|
49
|
+
if opts[:log_level]
|
50
|
+
opts[:log_level]
|
51
|
+
elsif opts[:quiet]
|
52
|
+
Logger::ERROR
|
53
|
+
elsif opts[:verbose]
|
54
|
+
Logger::DEBUG
|
55
|
+
else
|
56
|
+
Logger::INFO
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def log_level
|
62
|
+
@log_level || Logger::WARN
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def log_level=(lvl)
|
67
|
+
@log_level = lvl
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def workdir
|
72
|
+
@workdir
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def workdir=(dir)
|
77
|
+
workdir = GitLib.find_workdir(dir)
|
78
|
+
if workdir.nil?
|
79
|
+
@workdir = dir
|
80
|
+
logger.info { "Initializing new repository at #{dir}" }
|
81
|
+
command(:init)
|
82
|
+
else
|
83
|
+
@workdir = workdir
|
84
|
+
logger.debug { "Opening existing repository at #{dir}" }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def self.find_workdir(dir)
|
90
|
+
if dir == File::SEPARATOR
|
91
|
+
nil
|
92
|
+
elsif File.directory?(File.join(dir, '.git'))
|
93
|
+
dir
|
94
|
+
else
|
95
|
+
find_workdir(File.expand_path("#{dir}#{File::SEPARATOR}.."))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def config
|
101
|
+
if @config.nil?
|
102
|
+
@config = GitConfig.new(self)
|
103
|
+
end
|
104
|
+
@config
|
68
105
|
end
|
69
106
|
|
70
107
|
|
71
|
-
def
|
72
|
-
@
|
108
|
+
def remote
|
109
|
+
if @remote.nil?
|
110
|
+
@remote = GitProc::GitRemote.new(config)
|
111
|
+
end
|
112
|
+
@remote
|
73
113
|
end
|
74
114
|
|
75
115
|
|
76
116
|
# @return [Boolean] does this have a remote defined?
|
77
117
|
def has_a_remote?
|
78
|
-
|
79
|
-
@has_remote = (command(:remote) != '')
|
80
|
-
end
|
81
|
-
@has_remote
|
118
|
+
remote.exists?
|
82
119
|
end
|
83
120
|
|
84
121
|
|
@@ -89,7 +126,7 @@ module GitProc
|
|
89
126
|
|
90
127
|
|
91
128
|
def commit(msg = nil)
|
92
|
-
logger.info
|
129
|
+
logger.info 'Committing changes'
|
93
130
|
command(:commit, msg.nil? ? nil : ['-m', msg])
|
94
131
|
end
|
95
132
|
|
@@ -113,9 +150,60 @@ module GitProc
|
|
113
150
|
end
|
114
151
|
|
115
152
|
|
116
|
-
def fetch(name =
|
117
|
-
logger.info
|
118
|
-
command(:fetch, ['-p', name])
|
153
|
+
def fetch(name = remote.name)
|
154
|
+
logger.info 'Fetching the latest changes from the server'
|
155
|
+
output = self.command(:fetch, ['-p', name])
|
156
|
+
|
157
|
+
log_fetch_changes(fetch_changes(output))
|
158
|
+
|
159
|
+
output
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
# @param [Hash] changes a hash of the changes that were made
|
164
|
+
#
|
165
|
+
# @return [void]
|
166
|
+
def log_fetch_changes(changes)
|
167
|
+
changes.each do |key, v|
|
168
|
+
unless v.empty?
|
169
|
+
logger.info { " #{key.to_s.sub(/_/, ' ')}: #{v.join(', ')}" }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
# @return [Hash]
|
176
|
+
def fetch_changes(output)
|
177
|
+
changed = output.split("\n")
|
178
|
+
|
179
|
+
changes = {:new_branch => [], :new_tag => [], :force_updated => [], :deleted => [], :updated => []}
|
180
|
+
|
181
|
+
line = changed.shift
|
182
|
+
|
183
|
+
until line.nil? do
|
184
|
+
case line
|
185
|
+
when /^\s\s\s/
|
186
|
+
m = /^\s\s\s(\S+)\s+(\S+)\s/.match(line)
|
187
|
+
changes[:updated] << "#{m[2]} (#{m[1]})"
|
188
|
+
when /^\s\*\s\[new branch\]/
|
189
|
+
m = /^\s\*\s\[new branch\]\s+(\S+)\s/.match(line)
|
190
|
+
changes[:new_branch] << m[1]
|
191
|
+
when /^\s\*\s\[new tag\]/
|
192
|
+
m = /^\s\*\s\[new tag\]\s+(\S+)\s/.match(line)
|
193
|
+
changes[:new_tag] << m[1]
|
194
|
+
when /^\sx\s/
|
195
|
+
m = /^\sx\s\[deleted\]\s+\(none\)\s+->\s+[^\/]+\/(\S+)/.match(line)
|
196
|
+
changes[:deleted] << m[1]
|
197
|
+
when /^\s\+\s/
|
198
|
+
m = /^\s\+\s(\S+)\s+(\S+)\s/.match(line)
|
199
|
+
changes[:force_updated] << "#{m[2]} (#{m[1]})"
|
200
|
+
else
|
201
|
+
# ignore the line
|
202
|
+
end
|
203
|
+
line = changed.shift
|
204
|
+
end
|
205
|
+
|
206
|
+
changes
|
119
207
|
end
|
120
208
|
|
121
209
|
|
@@ -134,38 +222,27 @@ module GitProc
|
|
134
222
|
# @option opts [Boolean] :all list all branches, local and remote
|
135
223
|
# @option opts [Boolean] :no_color force not using any ANSI color codes
|
136
224
|
# @option opts [String] :rename the new name for the branch
|
225
|
+
# @option opts [String] :upstream the new branch to track
|
137
226
|
# @option opts [String] :base_branch the branch to base the new branch off of;
|
138
227
|
# defaults to 'master'
|
139
228
|
#
|
140
229
|
# @return [String] the output of running the git command
|
141
230
|
def branch(branch_name, opts = {})
|
142
|
-
args = []
|
143
231
|
if opts[:delete]
|
144
|
-
|
145
|
-
|
146
|
-
args << (opts[:force] ? '-D' : '-d')
|
147
|
-
args << branch_name
|
232
|
+
delete_branch(branch_name, opts[:force])
|
148
233
|
elsif opts[:rename]
|
149
|
-
|
150
|
-
|
151
|
-
|
234
|
+
rename_branch(branch_name, opts[:rename])
|
235
|
+
elsif opts[:upstream]
|
236
|
+
set_upstream_branch(branch_name, opts[:upstream])
|
152
237
|
elsif branch_name
|
153
238
|
if opts[:force]
|
154
|
-
|
155
|
-
logger.info { "Changing branch '#{branch_name}' to point to '#{opts[:base_branch]}'." }
|
156
|
-
|
157
|
-
args << '-f' << branch_name << opts[:base_branch]
|
239
|
+
change_branch(branch_name, opts[:base_branch])
|
158
240
|
else
|
159
|
-
|
160
|
-
|
161
|
-
args << branch_name
|
162
|
-
args << (opts[:base_branch] ? opts[:base_branch] : 'master')
|
241
|
+
create_branch(branch_name, opts[:base_branch])
|
163
242
|
end
|
164
243
|
else
|
165
|
-
|
166
|
-
args << '--no-color' if opts[:no_color]
|
244
|
+
list_branches(opts[:all], opts[:no_color])
|
167
245
|
end
|
168
|
-
command(:branch, args)
|
169
246
|
end
|
170
247
|
|
171
248
|
|
@@ -195,10 +272,10 @@ module GitProc
|
|
195
272
|
elsif !(opts[:delete].is_a? TrueClass)
|
196
273
|
rb = opts[:delete]
|
197
274
|
else
|
198
|
-
raise ArgumentError.new(
|
275
|
+
raise ArgumentError.new('Need a branch name to delete.')
|
199
276
|
end
|
200
277
|
|
201
|
-
int_branch = master_branch
|
278
|
+
int_branch = config.master_branch
|
202
279
|
if rb == int_branch
|
203
280
|
raise GitProc::GitProcessError.new("Can not delete the integration branch '#{int_branch}'")
|
204
281
|
end
|
@@ -278,69 +355,6 @@ module GitProc
|
|
278
355
|
end
|
279
356
|
|
280
357
|
|
281
|
-
def config_hash
|
282
|
-
@config_hash ||= {}
|
283
|
-
end
|
284
|
-
|
285
|
-
|
286
|
-
private :config_hash
|
287
|
-
|
288
|
-
|
289
|
-
def config(key = nil, value = nil, global = false)
|
290
|
-
if key and value
|
291
|
-
args = global ? %w(--global) : []
|
292
|
-
args << key << value
|
293
|
-
command(:config, args)
|
294
|
-
config_hash[key] = value unless config_hash.empty?
|
295
|
-
value
|
296
|
-
elsif key
|
297
|
-
value = config_hash[key]
|
298
|
-
unless value
|
299
|
-
value = command(:config, ['--get', key])
|
300
|
-
value = nil if value.empty?
|
301
|
-
config_hash[key] = value unless config_hash.empty?
|
302
|
-
end
|
303
|
-
value
|
304
|
-
else
|
305
|
-
if config_hash.empty?
|
306
|
-
str = command(:config, '--list')
|
307
|
-
lines = str.split("\n")
|
308
|
-
lines.each do |line|
|
309
|
-
(key, *values) = line.split('=')
|
310
|
-
config_hash[key] = values.join('=')
|
311
|
-
end
|
312
|
-
end
|
313
|
-
config_hash
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
|
318
|
-
def repo_name
|
319
|
-
unless @repo_name
|
320
|
-
origin_url = config("remote.#{remote_name}.url")
|
321
|
-
raise GitProc::Process::GitProcessError.new("There is no #{remote_name} url set up.") if origin_url.empty?
|
322
|
-
@repo_name = origin_url.sub(/^.*:(.*?)(.git)?$/, '\1')
|
323
|
-
end
|
324
|
-
@repo_name
|
325
|
-
end
|
326
|
-
|
327
|
-
|
328
|
-
def remote_name
|
329
|
-
unless @remote_name
|
330
|
-
@remote_name = config('gitProcess.remoteName')
|
331
|
-
if @remote_name.nil? or @remote_name.empty?
|
332
|
-
remote_str = command(:remote)
|
333
|
-
unless remote_str == nil or remote_str.empty?
|
334
|
-
@remote_name = remote_str.split(/\n/)[0]
|
335
|
-
raise "!@remote_name.is_a? String" unless @remote_name.is_a? String
|
336
|
-
end
|
337
|
-
end
|
338
|
-
logger.debug { "Using remote name of '#@remote_name'" }
|
339
|
-
end
|
340
|
-
@remote_name
|
341
|
-
end
|
342
|
-
|
343
|
-
|
344
358
|
#
|
345
359
|
# Returns the status of the git repository.
|
346
360
|
#
|
@@ -367,28 +381,6 @@ module GitProc
|
|
367
381
|
end
|
368
382
|
|
369
383
|
|
370
|
-
def rerere_enabled?
|
371
|
-
re = config('rerere.enabled')
|
372
|
-
re && re.to_boolean
|
373
|
-
end
|
374
|
-
|
375
|
-
|
376
|
-
def rerere_enabled(re, global = true)
|
377
|
-
config('rerere.enabled', re, global)
|
378
|
-
end
|
379
|
-
|
380
|
-
|
381
|
-
def rerere_autoupdate?
|
382
|
-
re = config('rerere.autoupdate')
|
383
|
-
re && re.to_boolean
|
384
|
-
end
|
385
|
-
|
386
|
-
|
387
|
-
def rerere_autoupdate(re, global = true)
|
388
|
-
config('rerere.autoupdate', re, global)
|
389
|
-
end
|
390
|
-
|
391
|
-
|
392
384
|
def rev_list(start_revision, end_revision, opts ={})
|
393
385
|
args = []
|
394
386
|
args << "-#{opts[:num_revs]}" if opts[:num_revs]
|
@@ -406,40 +398,52 @@ module GitProc
|
|
406
398
|
alias sha rev_parse
|
407
399
|
|
408
400
|
|
409
|
-
|
410
|
-
|
401
|
+
# @return [String]
|
402
|
+
def command(cmd, opts = [], chdir = true, redirect = '', &block)
|
403
|
+
ENV['GIT_INDEX_FILE'] = File.join(workdir, '.git', 'index')
|
404
|
+
ENV['GIT_DIR'] = File.join(workdir, '.git')
|
405
|
+
ENV['GIT_WORK_TREE'] = workdir
|
406
|
+
path = workdir
|
407
|
+
|
408
|
+
git_cmd = create_git_command(cmd, opts, redirect)
|
409
|
+
|
410
|
+
out = command_git_cmd(path, git_cmd, chdir, block)
|
411
|
+
|
412
|
+
if logger
|
413
|
+
logger.debug(git_cmd)
|
414
|
+
logger.debug(out)
|
415
|
+
end
|
416
|
+
|
417
|
+
handle_exitstatus($?, git_cmd, out)
|
411
418
|
end
|
412
419
|
|
413
420
|
|
414
421
|
private
|
415
422
|
|
416
423
|
|
417
|
-
def
|
418
|
-
ENV['GIT_DIR'] = File.join(workdir, '.git')
|
419
|
-
ENV['GIT_INDEX_FILE'] = File.join(workdir, '.git', 'index')
|
420
|
-
ENV['GIT_WORK_TREE'] = workdir
|
421
|
-
path = workdir
|
422
|
-
|
424
|
+
def create_git_command(cmd, opts, redirect)
|
423
425
|
opts = [opts].flatten.map { |s| escape(s) }.join(' ')
|
424
|
-
|
426
|
+
"git #{cmd} #{opts} #{redirect} 2>&1"
|
427
|
+
end
|
425
428
|
|
429
|
+
|
430
|
+
def command_git_cmd(path, git_cmd, chdir, block)
|
426
431
|
out = nil
|
427
432
|
if chdir and (Dir.getwd != path)
|
428
433
|
Dir.chdir(path) { out = run_command(git_cmd, &block) }
|
429
434
|
else
|
430
435
|
out = run_command(git_cmd, &block)
|
431
436
|
end
|
437
|
+
out
|
438
|
+
end
|
432
439
|
|
433
|
-
if logger
|
434
|
-
logger.debug(git_cmd)
|
435
|
-
logger.debug(out)
|
436
|
-
end
|
437
440
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
+
# @return [String]
|
442
|
+
def handle_exitstatus(proc_status, git_cmd, out)
|
443
|
+
if proc_status.exitstatus > 0
|
444
|
+
unless proc_status.exitstatus == 1 && out == ''
|
445
|
+
raise GitProc::GitExecuteError.new(git_cmd + ':' + out.to_s)
|
441
446
|
end
|
442
|
-
raise GitProc::GitExecuteError.new(git_cmd + ':' + out.to_s)
|
443
447
|
end
|
444
448
|
out
|
445
449
|
end
|
@@ -459,6 +463,50 @@ module GitProc
|
|
459
463
|
%Q{"#{escaped}"}
|
460
464
|
end
|
461
465
|
|
466
|
+
|
467
|
+
def change_branch(branch_name, base_branch)
|
468
|
+
raise ArgumentError.new('Need :base_branch when using :force for a branch.') unless base_branch
|
469
|
+
logger.info { "Changing branch '#{branch_name}' to point to '#{base_branch}'." }
|
470
|
+
|
471
|
+
command(:branch, ['-f', branch_name, base_branch])
|
472
|
+
end
|
473
|
+
|
474
|
+
|
475
|
+
def create_branch(branch_name, base_branch)
|
476
|
+
logger.info { "Creating new branch '#{branch_name}' based on '#{base_branch}'." }
|
477
|
+
|
478
|
+
command(:branch, [branch_name, (base_branch || 'master')])
|
479
|
+
end
|
480
|
+
|
481
|
+
|
482
|
+
def list_branches(all_branches, no_color)
|
483
|
+
args = []
|
484
|
+
args << '-a' if all_branches
|
485
|
+
args << '--no-color' if no_color
|
486
|
+
command(:branch, args)
|
487
|
+
end
|
488
|
+
|
489
|
+
|
490
|
+
def delete_branch(branch_name, force)
|
491
|
+
logger.info { "Deleting local branch '#{branch_name}'." } unless branch_name == '_parking_'
|
492
|
+
|
493
|
+
command(:branch, [force ? '-D' : '-d', branch_name])
|
494
|
+
end
|
495
|
+
|
496
|
+
|
497
|
+
def rename_branch(branch_name, new_name)
|
498
|
+
logger.info { "Renaming branch '#{branch_name}' to '#{new_name}'." }
|
499
|
+
|
500
|
+
command(:branch, ['-m', branch_name, new_name])
|
501
|
+
end
|
502
|
+
|
503
|
+
|
504
|
+
def set_upstream_branch(branch_name, upstream)
|
505
|
+
logger.info { "Setting upstream/tracking for branch '#{branch_name}' to '#{upstream}'." }
|
506
|
+
|
507
|
+
command(:branch, ['--set-upstream-to', upstream, branch_name])
|
508
|
+
end
|
509
|
+
|
462
510
|
end
|
463
511
|
|
464
512
|
end
|