git_commands 3.4.0 → 3.5.1
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.
- 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
|