git_commands 3.4.0 → 3.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +49 -14
- data/lib/git_commands/aggregator.rb +43 -0
- data/lib/git_commands/branch.rb +9 -9
- data/lib/git_commands/cli.rb +12 -8
- data/lib/git_commands/computer.rb +26 -20
- data/lib/git_commands/prompt.rb +1 -1
- data/lib/git_commands/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 172e8dcb4ab65fc7f43efc68e42709b8730fb54b
|
4
|
+
data.tar.gz: 8a9fa030b351e83b13e3dd4ea7a5c0684670a05d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0adf55993c9add401986a9d019e712998813b087bcbbb27bcb339daaddab77a9c2ba3ddb8af7191c884462b6f7c05e55591323b7cd30dd96c5f4679cf1d7d070
|
7
|
+
data.tar.gz: 5222cf662d765a7fd08cbd31bb357abe849f2b5c42974c599a1b5e1462b4cb065720c58b5f6eb0a4d74298af3e770bf87efd97a7a7f35092be5b59084906fa3e
|
data/README.md
CHANGED
@@ -16,9 +16,8 @@
|
|
16
16
|
## Workflow
|
17
17
|
This script facilitates adopting a subset of the branch-featuring workflow characterised by:
|
18
18
|
* each feature will have its own branch
|
19
|
-
* feature
|
20
|
-
*
|
21
|
-
* force pushing of feature branches to origin is not an issue
|
19
|
+
* integration of feature branch with defaukt one happens via rebasing to maintain a straight commits line
|
20
|
+
* is not an issue to `force-with-lease` push feature pranch to origin
|
22
21
|
* release branches are created aggregating multiple branches
|
23
22
|
|
24
23
|
## Scope
|
@@ -48,10 +47,11 @@ Display the help of a specific command by:
|
|
48
47
|
|
49
48
|
```
|
50
49
|
rebase --help
|
51
|
-
Usage: rebase --repo=/Users/Elvis/greatest_hits --branches=feature/love_me_tender,fetaure/teddybear
|
50
|
+
Usage: rebase --repo=/Users/Elvis/greatest_hits --origin=upstream --default=production --branches=feature/love_me_tender,fetaure/teddybear
|
52
51
|
-r, --repo=REPO The path to the existing GIT repository
|
52
|
+
-o, --origin=ORIGIN Specify the remote alias (origin)
|
53
|
+
-d, --default=DEFAULT Specify the default branch (master)
|
53
54
|
-b, --branches=BRANCHES Specify branches as: 1. a comma-separated list of names 2. the path to a file containing names on each line 3. via pattern matching
|
54
|
-
-t, --target=TARGET Specify the target branch, default to master
|
55
55
|
-h, --help Prints this help
|
56
56
|
```
|
57
57
|
|
@@ -133,8 +133,8 @@ rebase --repo=/Users/Elvis/greatest_hits --branches=noent1,noent2
|
|
133
133
|
No branches loaded!
|
134
134
|
```
|
135
135
|
|
136
|
-
#####
|
137
|
-
|
136
|
+
##### Default branch
|
137
|
+
Default branch cannot be included into the branches list for obvious reasons:
|
138
138
|
|
139
139
|
```
|
140
140
|
rebase --repo=/Users/Elvis/greatest_hits --branches=master,feature/love_me_tender
|
@@ -148,7 +148,7 @@ Successfully loaded 1 branch:
|
|
148
148
|
Here are the available GIT commands:
|
149
149
|
|
150
150
|
#### Rebase
|
151
|
-
This command is useful in case you have several branches
|
151
|
+
This command is useful in case you have to rebase several branches with _origin/master_ (or another specified default) frequently.
|
152
152
|
A confirmation is asked to before rebasing.
|
153
153
|
|
154
154
|
```
|
@@ -156,17 +156,17 @@ rebase --repo=/Users/Elvis/greatest_hits --branches=feature/love_me_tender,featu
|
|
156
156
|
...
|
157
157
|
```
|
158
158
|
|
159
|
-
#####
|
160
|
-
The rebasing runs considering master branch as the
|
161
|
-
In case you need to rebase against a different
|
159
|
+
##### Changing origin
|
160
|
+
The rebasing runs considering `master` branch as the default one and `origin` as the remote alias.
|
161
|
+
In case you need to rebase against a different origin and default branch you can specify them by command line:
|
162
162
|
```
|
163
|
-
rebase --repo=/Users/Elvis/greatest_hits --
|
163
|
+
rebase --repo=/Users/Elvis/greatest_hits --origin=upstream --default=production --branches=feature/love_me_tender
|
164
164
|
|
165
165
|
Loading branches file...
|
166
166
|
Successfully loaded 1 branch:
|
167
167
|
01. feature/love_me_tender
|
168
168
|
|
169
|
-
Proceed rebasing these branches with
|
169
|
+
Proceed rebasing these branches with upstream/production (Y/N)?
|
170
170
|
```
|
171
171
|
|
172
172
|
#### Remove
|
@@ -180,10 +180,45 @@ remove --repo=/temp/top_20 --branches=*obsolete*
|
|
180
180
|
|
181
181
|
#### Aggregate
|
182
182
|
This command aggregates all of the specified branches into a single one in case you want to create a release branch.
|
183
|
-
The created aggregate branch follows this naming convention: *aggregate/yyyy_mm_dd*
|
184
183
|
A confirmation is asked before aggregating.
|
185
184
|
|
186
185
|
```
|
187
186
|
aggregate --repo=/Users/Elvis/greatest_hits --branches=*ready*
|
188
187
|
...
|
189
188
|
```
|
189
|
+
|
190
|
+
##### Aggregate naming
|
191
|
+
The created aggregate branch follows a default naming convention pattern:
|
192
|
+
`aggregate/<timestamp>`
|
193
|
+
|
194
|
+
Each of the term within the `<` and `>` chars are replaced by related (upcased) environment variables, but for the `timestamp`, that is computed at runtime in the `yyyymmdd` format.
|
195
|
+
Consider a valid pattern should at least contain one replaceable part within the `<` and `>` chars.
|
196
|
+
|
197
|
+
You can overwrite the naming pattern by specifying the following environment variables:
|
198
|
+
* `AGGREGATE_NAME` - the name to be used directly for the aggregator branch, without any pattern replacements
|
199
|
+
* `AGGREGATE_PATTERN` - change the default pattern by specifying the related environment variables for each parts within the `<` and `>` chars
|
200
|
+
|
201
|
+
###### Examples
|
202
|
+
Passing directly the aggregate name:
|
203
|
+
```shell
|
204
|
+
AGGREGATE_NAME=my_aggregate aggregate --repo=/Users/Elvis/greatest_hits --branches=*ready*
|
205
|
+
...
|
206
|
+
Aggregate branches into my_aggregate (Y/N)?
|
207
|
+
```
|
208
|
+
|
209
|
+
Using the default pattern:
|
210
|
+
```shell
|
211
|
+
aggregate --repo=/Users/Elvis/greatest_hits --branches=*ready*
|
212
|
+
...
|
213
|
+
Aggregate branches into release/20170307 (Y/N)?
|
214
|
+
```
|
215
|
+
|
216
|
+
Using a custom pattern:
|
217
|
+
```shell
|
218
|
+
RELEASE_TYPE=bugfix \
|
219
|
+
RISK=HIGH \
|
220
|
+
PROGRESSIVE=3 \
|
221
|
+
AGGREGATE_PATTERN="release/rc-<progressive>.<release_type>_<risk>_<timestamp>" aggregate --repo=/Users/Elvis/greatest_hits --branches=*ready*
|
222
|
+
...
|
223
|
+
Aggregate branches into release/rc-3.bugfix_HIGH_20170307 (Y/N)?
|
224
|
+
```
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module GitCommands
|
2
|
+
class Aggregator
|
3
|
+
PATTERN = ENV.fetch("AGGREGATE_PATTERN") { "release/<timestamp>" }
|
4
|
+
NAME = ENV["AGGREGATE_NAME"]
|
5
|
+
|
6
|
+
class InvalidPatternError < ArgumentError; end
|
7
|
+
|
8
|
+
def initialize(name: NAME, pattern: PATTERN)
|
9
|
+
@name = name
|
10
|
+
@pattern = check_pattern(pattern)
|
11
|
+
define_methods
|
12
|
+
end
|
13
|
+
|
14
|
+
def timestamp
|
15
|
+
@timestamp ||= Time.new.strftime("%Y%m%d")
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
return @name if @name
|
20
|
+
@pattern.gsub(/<[\w_]+>/) do |part|
|
21
|
+
msg = part.gsub(/<|>/, "")
|
22
|
+
send(msg)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private def check_pattern(pattern)
|
27
|
+
fail InvalidPatternError unless pattern.match(/<\w+>/)
|
28
|
+
pattern
|
29
|
+
end
|
30
|
+
|
31
|
+
private def pattern_methods
|
32
|
+
@methods ||= @pattern.scan(/<(\w+)>/).flatten - ["timestamp"]
|
33
|
+
end
|
34
|
+
|
35
|
+
def define_methods
|
36
|
+
pattern_methods.each do |name|
|
37
|
+
define_singleton_method(name) do
|
38
|
+
ENV.fetch(name.upcase) { "" }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/git_commands/branch.rb
CHANGED
@@ -3,11 +3,11 @@ require "pathname"
|
|
3
3
|
module GitCommands
|
4
4
|
using Colorize
|
5
5
|
class Branch
|
6
|
-
|
7
|
-
ORIGIN = "origin
|
6
|
+
DEFAULT = "master"
|
7
|
+
ORIGIN = "origin"
|
8
8
|
|
9
9
|
def self.strip_origin(name)
|
10
|
-
name.strip.split(ORIGIN).last
|
10
|
+
name.strip.split("#{ORIGIN}/").last
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.by_file(path)
|
@@ -19,9 +19,9 @@ module GitCommands
|
|
19
19
|
|
20
20
|
def self.by_pattern(pattern)
|
21
21
|
return [] unless pattern.index("*")
|
22
|
-
`git branch -r --list #{ORIGIN}
|
22
|
+
`git branch -r --list #{ORIGIN}/#{pattern}`.split("\n").map do |name|
|
23
23
|
new(strip_origin(name))
|
24
|
-
end.reject(&:
|
24
|
+
end.reject(&:default?)
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.by_names(names_list)
|
@@ -54,7 +54,7 @@ module GitCommands
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def valid?
|
57
|
-
return false if
|
57
|
+
return false if default?
|
58
58
|
return false unless exists?
|
59
59
|
true
|
60
60
|
end
|
@@ -63,12 +63,12 @@ module GitCommands
|
|
63
63
|
self.name == other.name
|
64
64
|
end
|
65
65
|
|
66
|
-
def
|
67
|
-
@name ==
|
66
|
+
def default?
|
67
|
+
@name == DEFAULT
|
68
68
|
end
|
69
69
|
|
70
70
|
def exists?(remote = true)
|
71
|
-
origin = ORIGIN if remote
|
71
|
+
origin = "#{ORIGIN}/" if remote
|
72
72
|
`git rev-parse --verify #{origin}#{@name} 2> /dev/null`.match(/^[0-9a-z]+/)
|
73
73
|
end
|
74
74
|
end
|
data/lib/git_commands/cli.rb
CHANGED
@@ -20,15 +20,15 @@ module GitCommands
|
|
20
20
|
|
21
21
|
def call
|
22
22
|
parser.parse!(@args)
|
23
|
-
computer = @computer_klass.new(repo: @repo, branches: @branches,
|
23
|
+
computer = @computer_klass.new(repo: @repo, branches: @branches, origin: @origin, default: default)
|
24
24
|
computer.send(@command_name)
|
25
25
|
rescue Repository::PathError, Computer::GitError, AbortError, Repository::InvalidError => e
|
26
26
|
error(e.message)
|
27
27
|
exit
|
28
28
|
end
|
29
29
|
|
30
|
-
private def
|
31
|
-
@
|
30
|
+
private def default
|
31
|
+
@default || Branch::DEFAULT
|
32
32
|
end
|
33
33
|
|
34
34
|
private def check_command_name(name)
|
@@ -38,18 +38,22 @@ module GitCommands
|
|
38
38
|
|
39
39
|
private def parser
|
40
40
|
OptionParser.new do |opts|
|
41
|
-
opts.banner = "Usage: #{@command_name} --repo=/Users/Elvis/greatest_hits --branches=feature/love_me_tender,fetaure/teddybear"
|
41
|
+
opts.banner = "Usage: #{@command_name} --repo=/Users/Elvis/greatest_hits --origin=upstream --default=production --branches=feature/love_me_tender,fetaure/teddybear"
|
42
42
|
|
43
43
|
opts.on("-rREPO", "--repo=REPO", "The path to the existing GIT repository") do |repo|
|
44
44
|
@repo = repo
|
45
45
|
end
|
46
46
|
|
47
|
-
opts.on("-
|
48
|
-
@
|
47
|
+
opts.on("-oORIGIN", "--origin=ORIGIN", "Specify the remote alias (origin)") do |origin|
|
48
|
+
@origin = origin
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("-dDEFAULT", "--default=DEFAULT", "Specify the default branch (master)") do |default|
|
52
|
+
@default = default
|
49
53
|
end
|
50
54
|
|
51
|
-
opts.on("-
|
52
|
-
@
|
55
|
+
opts.on("-bBRANCHES", "--branches=BRANCHES", "Specify branches as: 1. a comma-separated list of names 2. the path to a file containing names on each line 3. via pattern matching") do |branches|
|
56
|
+
@branches = branches
|
53
57
|
end
|
54
58
|
|
55
59
|
opts.on("-h", "--help", "Prints this help") do
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "git_commands/prompt"
|
2
2
|
require "git_commands/branch"
|
3
3
|
require "git_commands/repository"
|
4
|
+
require "git_commands/aggregator"
|
4
5
|
|
5
6
|
module GitCommands
|
6
7
|
class Computer
|
@@ -9,15 +10,14 @@ module GitCommands
|
|
9
10
|
class GitError < StandardError; end
|
10
11
|
|
11
12
|
attr_reader :out
|
12
|
-
attr_accessor :target
|
13
13
|
|
14
|
-
def initialize(repo:, branches:,
|
14
|
+
def initialize(repo:, branches:, origin: Branch::ORIGIN, default: Branch::DEFAULT, repo_klass: Repository, branch_klass: Branch, out: STDOUT)
|
15
15
|
@out = out
|
16
16
|
@repo = repo_klass.new(repo)
|
17
|
-
@
|
17
|
+
@origin = origin
|
18
|
+
@default = default
|
18
19
|
Dir.chdir(@repo) do
|
19
20
|
@branches = branch_klass.factory(branches)
|
20
|
-
@timestamp = Time.new.strftime("%Y-%m-%d")
|
21
21
|
print_branches
|
22
22
|
end
|
23
23
|
end
|
@@ -35,14 +35,14 @@ module GitCommands
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def rebase
|
38
|
-
confirm("Proceed rebasing these branches with #{
|
38
|
+
confirm("Proceed rebasing these branches with: #{local_def}") do
|
39
39
|
enter_repo do
|
40
40
|
@branches.each do |branch|
|
41
41
|
warning("Rebasing branch: #{branch}")
|
42
42
|
`git checkout #{branch}`
|
43
|
-
`git pull origin #{branch}`
|
43
|
+
`git pull -r origin #{branch}`
|
44
44
|
next unless rebase_with
|
45
|
-
`git push -
|
45
|
+
`git push --force-with-lease origin #{branch}`
|
46
46
|
success("Rebased successfully!")
|
47
47
|
end
|
48
48
|
remove_locals
|
@@ -50,23 +50,23 @@ module GitCommands
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def aggregate
|
54
|
-
temp = "temp/#{
|
55
|
-
|
56
|
-
confirm("Aggregate branches into #{
|
53
|
+
def aggregate(aggregator = Aggregator.new)
|
54
|
+
temp = "temp/#{aggregator.timestamp}"
|
55
|
+
aggregate_name = aggregator.call
|
56
|
+
confirm("Aggregate branches into #{aggregate_name}") do
|
57
57
|
enter_repo do
|
58
|
-
`git branch #{
|
58
|
+
`git branch #{aggregate_name}`
|
59
59
|
@branches.each do |branch|
|
60
60
|
warning("Merging branch: #{branch}")
|
61
61
|
`git checkout -b #{temp} origin/#{branch} --no-track`
|
62
|
-
clean_and_exit([temp,
|
63
|
-
clean_and_exit([temp]) unless rebase_with(
|
64
|
-
`git checkout #{
|
62
|
+
clean_and_exit([temp, aggregate_name]) unless rebase_with
|
63
|
+
clean_and_exit([temp]) unless rebase_with(aggregate_name)
|
64
|
+
`git checkout #{aggregate_name}`
|
65
65
|
`git merge #{temp}`
|
66
66
|
`git branch -D #{temp}`
|
67
67
|
end
|
68
68
|
end
|
69
|
-
success("#{
|
69
|
+
success("#{aggregate_name} branch created")
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -79,11 +79,13 @@ module GitCommands
|
|
79
79
|
end
|
80
80
|
|
81
81
|
private def align
|
82
|
-
`git
|
83
|
-
`git
|
82
|
+
`git fetch #{@origin} #{@default}`
|
83
|
+
`git fetch origin`
|
84
|
+
`git checkout #{@default}`
|
85
|
+
`git pull -r`
|
84
86
|
end
|
85
87
|
|
86
|
-
private def rebase_with(branch =
|
88
|
+
private def rebase_with(branch = local_def)
|
87
89
|
`git rebase #{branch}`
|
88
90
|
return true unless @repo.locked?
|
89
91
|
@repo.unlock
|
@@ -98,7 +100,7 @@ module GitCommands
|
|
98
100
|
end
|
99
101
|
|
100
102
|
private def remove_locals(branches = @branches)
|
101
|
-
`git checkout #{@
|
103
|
+
`git checkout #{@default}`
|
102
104
|
branches.each do |branch|
|
103
105
|
`git branch -D #{branch}`
|
104
106
|
end
|
@@ -108,5 +110,9 @@ module GitCommands
|
|
108
110
|
remove_locals(branches)
|
109
111
|
exit
|
110
112
|
end
|
113
|
+
|
114
|
+
private def local_def
|
115
|
+
"#{@origin}/#{@default}"
|
116
|
+
end
|
111
117
|
end
|
112
118
|
end
|
data/lib/git_commands/prompt.rb
CHANGED
data/lib/git_commands/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git_commands
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- costajob
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- bin/setup
|
76
76
|
- git_commands.gemspec
|
77
77
|
- lib/git_commands.rb
|
78
|
+
- lib/git_commands/aggregator.rb
|
78
79
|
- lib/git_commands/branch.rb
|
79
80
|
- lib/git_commands/cli.rb
|
80
81
|
- lib/git_commands/colorize.rb
|