git-maintain 0.7.0 → 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG +14 -0
- data/LICENSE +674 -22
- data/README.md +26 -5
- data/lib/addons/RDMACore.rb +54 -3
- data/lib/branch.rb +84 -49
- data/lib/ci.rb +88 -0
- data/lib/common.rb +16 -11
- data/lib/repo.rb +143 -68
- data/lib/travis.rb +18 -61
- metadata +16 -8
data/README.md
CHANGED
@@ -16,9 +16,9 @@ The idea is to script most of the maintenance tasks so the maintainer can focus
|
|
16
16
|
- **list_stable**: List commit present in the stable branch but not in the latest associated relase
|
17
17
|
- **merge**: Merge branch with suffix specified in -m <suff> into the main branch
|
18
18
|
- **push**: Push branches to github for validation
|
19
|
-
- **monitor**: Check the
|
19
|
+
- **monitor**: Check the CI state of all branches
|
20
20
|
- **push_stable**: Push to stable repo
|
21
|
-
- **monitor_stable**: Check the
|
21
|
+
- **monitor_stable**: Check the CI state of all stable branches
|
22
22
|
- **release**: Create new release on all concerned branches
|
23
23
|
- **reset**: Reset branch against upstream
|
24
24
|
- **submit_release**: Push the to stable and create the release packages
|
@@ -157,7 +157,7 @@ Apply them to the appropriate branches
|
|
157
157
|
|
158
158
|
```git maintain cp -s deadbeef --version '1[789]'```
|
159
159
|
|
160
|
-
And push them to my own github repo so that
|
160
|
+
And push them to my own github repo so that CI will check everything out
|
161
161
|
|
162
162
|
```git maintain push --version '1[789]'```
|
163
163
|
|
@@ -179,7 +179,7 @@ Push it to my own github too.
|
|
179
179
|
|
180
180
|
```git maintain push --version '1[789]' -b pending```
|
181
181
|
|
182
|
-
Once this gets accepted (and
|
182
|
+
Once this gets accepted (and CI is OK too), I merge this branch back to my 'master'
|
183
183
|
|
184
184
|
```git maintain merge --version '1[789]' -m pending```
|
185
185
|
|
@@ -239,7 +239,7 @@ The tag will not have been propagated anywhere else and can be deleted manually.
|
|
239
239
|
|
240
240
|
```git maintain push_stable --version '1[789]'```
|
241
241
|
|
242
|
-
You can then monitor the status on
|
242
|
+
You can then monitor the status on CI
|
243
243
|
|
244
244
|
```git maintain monitor_stable --version '1[789]'```
|
245
245
|
|
@@ -258,6 +258,8 @@ Enjoy, and feel free to report bugs, missing features and/or send patches
|
|
258
258
|
|
259
259
|
This is a summary of all the settings that can be set in the git config:
|
260
260
|
|
261
|
+
- `maintain.valid-repo`: Remote github repo to test out branches before submitting. Default = `github`
|
262
|
+
- `maintain.stable-repo`: Remote stable github repository t submit validated branches and new releases. Default = `stable`
|
261
263
|
- `maintain.autofetch`: Enable/Disable auto fetching.
|
262
264
|
Can be overriden by the --[no-]fetch option on the CLI.
|
263
265
|
If unset, autofetch is enabled
|
@@ -274,3 +276,22 @@ This is a summary of all the settings that can be set in the git config:
|
|
274
276
|
- `maintain.mail-format`: Specify how release annoucement emails are sent. Can be:
|
275
277
|
- `imap_send`: Store prepared email in an IMAP folder. See `main git-imap-send` for more infos. This is the default value.
|
276
278
|
- `send_email`: Generates a file which is compatible with git send-email
|
279
|
+
|
280
|
+
# License
|
281
|
+
|
282
|
+
Unless otherwise stated, everything in this repo is covered by the following
|
283
|
+
copyright notice:
|
284
|
+
|
285
|
+
Copyright (c) 2018 SUSE
|
286
|
+
|
287
|
+
This program is free software: you can redistribute it and/or modify it
|
288
|
+
under the terms of the GNU General Public License version 3, as
|
289
|
+
published by the Free Software Foundation.
|
290
|
+
|
291
|
+
This program is distributed in the hope that it will be useful,
|
292
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
293
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
294
|
+
GNU General Public License for more details.
|
295
|
+
|
296
|
+
You should have received a copy of the GNU General Public License
|
297
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/lib/addons/RDMACore.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module GitMaintain
|
2
2
|
class RDMACoreBranch < Branch
|
3
3
|
REPO_NAME = "rdma-core"
|
4
|
+
AZURE_MIN_VERSION = 25
|
4
5
|
|
5
6
|
def self.set_opts(action, optsParser, opts)
|
6
7
|
opts[:rel_type] = nil
|
@@ -73,7 +74,7 @@ module GitMaintain
|
|
73
74
|
end
|
74
75
|
|
75
76
|
# Update version number in relevant files
|
76
|
-
@repo.run("sed -i -e 's/\\(Version:[[:space:]]*\\)[0-9.]\\+/\\1#{new_ver}/g'
|
77
|
+
@repo.run("sed -i -e 's/\\(Version:[[:space:]]*\\)[0-9.]\\+/\\1#{new_ver}/g' */*.spec")
|
77
78
|
@repo.run("sed -i -e 's/\\([sS][eE][tT](PACKAGE_VERSION[[:space:]]*\"\\)[0-9.]*\"/\\1#{new_ver}\"/g' CMakeLists.txt")
|
78
79
|
|
79
80
|
case opts[:rel_type]
|
@@ -93,7 +94,7 @@ mv debian/changelog.new debian/changelog")
|
|
93
94
|
end
|
94
95
|
|
95
96
|
# Add and commit
|
96
|
-
@repo.runGit("add
|
97
|
+
@repo.runGit("add */*.spec CMakeLists.txt debian/changelog")
|
97
98
|
@repo.runGitInteractive("commit -m '#{commit_msg} #{new_ver}' --verbose --edit --signoff")
|
98
99
|
if $? != 0 then
|
99
100
|
raise("Failed to commit on branch #{local_branch}")
|
@@ -108,7 +109,57 @@ mv debian/changelog.new debian/changelog")
|
|
108
109
|
`rm -f #{tag_path}`
|
109
110
|
end
|
110
111
|
end
|
112
|
+
class RDMACoreRepo < Repo
|
113
|
+
AZURE_MIN_VERSION = 25
|
114
|
+
def submitReleases(opts, new_tags)
|
115
|
+
new_tags.each(){|tag|
|
116
|
+
next if tag !~ /v([0-9]*)\.[0-9]*/
|
117
|
+
major=$1.to_i
|
118
|
+
# Starting from v27, do not create the github release ourself as this is done by Azure
|
119
|
+
createRelease(opts, tag, major < AZURE_MIN_VERSION)
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class RDMACoreCI < CI
|
125
|
+
AZURE_MIN_VERSION = 25
|
126
|
+
def initialize(repo)
|
127
|
+
super(repo)
|
128
|
+
@travis = GitMaintain::TravisCI.new(repo)
|
129
|
+
@azure = GitMaintain::AzureCI.new(repo, 'ucfconsort', 'ucfconsort')
|
130
|
+
|
131
|
+
# Auto generate all CI required methods
|
132
|
+
# Wicked ruby tricker to find all the public methods of CI but not of inherited classes
|
133
|
+
# to dynamically define these method in the object being created
|
134
|
+
(GitMaintain::CI.new(repo).public_methods() - Object.new.public_methods()).each(){|method|
|
135
|
+
# Skip specific emptyCache method
|
136
|
+
next if method == :emptyCache
|
111
137
|
|
138
|
+
self.define_singleton_method(method) { |br, *args|
|
139
|
+
if br.version =~ /([0-9]+)/
|
140
|
+
major=$1.to_i
|
141
|
+
elsif br.version == "master"
|
142
|
+
major=99999
|
143
|
+
else
|
144
|
+
raise("Unable to monitor branch #{br} on a CI")
|
145
|
+
end
|
146
|
+
if major < AZURE_MIN_VERSION
|
147
|
+
@travis.send(method, br, *args)
|
148
|
+
else
|
149
|
+
@azure.send(method, br, *args)
|
150
|
+
end
|
151
|
+
}
|
152
|
+
}
|
153
|
+
end
|
154
|
+
def emptyCache()
|
155
|
+
@travis.emptyCache()
|
156
|
+
@azure.emptyCache()
|
157
|
+
end
|
158
|
+
end
|
112
159
|
GitMaintain::registerCustom(RDMACoreBranch::REPO_NAME,
|
113
|
-
{
|
160
|
+
{
|
161
|
+
GitMaintain::Branch => RDMACoreBranch,
|
162
|
+
GitMaintain::Repo => RDMACoreRepo,
|
163
|
+
GitMaintain::CI => RDMACoreCI,
|
164
|
+
})
|
114
165
|
end
|
data/lib/branch.rb
CHANGED
@@ -33,34 +33,35 @@ module GitMaintain
|
|
33
33
|
"* list_stable: List commit present in the stable branch but not in the latest associated relase",
|
34
34
|
"* merge: Merge branch with suffix specified in -m <suff> into the main branch",
|
35
35
|
"* push: Push branches to github for validation",
|
36
|
-
"* monitor: Check the
|
36
|
+
"* monitor: Check the CI state of all branches",
|
37
37
|
"* push_stable: Push to stable repo",
|
38
|
-
"* monitor_stable: Check the
|
38
|
+
"* monitor_stable: Check the CI state of all stable branches",
|
39
39
|
"* release: Create new release on all concerned branches",
|
40
40
|
"* reset: Reset branch against upstream",
|
41
41
|
]
|
42
42
|
|
43
|
-
def self.load(repo, version,
|
43
|
+
def self.load(repo, version, ci, branch_suff)
|
44
44
|
repo_name = File.basename(repo.path)
|
45
|
-
return GitMaintain::loadClass(Branch, repo_name, repo, version,
|
45
|
+
return GitMaintain::loadClass(Branch, repo_name, repo, version, ci, branch_suff)
|
46
46
|
end
|
47
47
|
|
48
48
|
def self.set_opts(action, optsParser, opts)
|
49
49
|
opts[:base_ver] = 0
|
50
|
-
opts[:version] =
|
50
|
+
opts[:version] = []
|
51
51
|
opts[:commits] = []
|
52
52
|
opts[:do_merge] = false
|
53
53
|
opts[:push_force] = false
|
54
|
-
opts[:
|
54
|
+
opts[:no_ci] = false
|
55
55
|
opts[:all] = false
|
56
56
|
opts[:check_only] = false
|
57
57
|
opts[:fetch] = nil
|
58
58
|
opts[:watch] = false
|
59
|
+
opts[:delete_remote] = false
|
59
60
|
|
60
61
|
optsParser.on("-v", "--base-version [MIN_VER]", Integer, "Older release to consider.") {
|
61
62
|
|val| opts[:base_ver] = val}
|
62
63
|
optsParser.on("-V", "--version [regexp]", Regexp, "Regexp to filter versions.") {
|
63
|
-
|val| opts[:version]
|
64
|
+
|val| opts[:version] << val}
|
64
65
|
|
65
66
|
if ALL_BRANCHES_ACTIONS.index(action) == nil &&
|
66
67
|
action != :merge &&
|
@@ -79,13 +80,16 @@ module GitMaintain
|
|
79
80
|
optsParser.banner += "-c <sha1> [-c <sha1> ...]"
|
80
81
|
optsParser.on("-c", "--sha1 [SHA1]", String, "Commit to cherry-pick. Can be used multiple time.") {
|
81
82
|
|val| opts[:commits] << val}
|
83
|
+
when :delete
|
84
|
+
optsParser.on("--remote", "Delete the remote staging branch instead of the local ones.") {
|
85
|
+
|val| opts[:delete_remote] = true}
|
82
86
|
when :merge
|
83
87
|
optsParser.banner += "-m <suffix>"
|
84
88
|
optsParser.on("-m", "--merge [SUFFIX]", "Merge branch with suffix.") {
|
85
89
|
|val| opts[:do_merge] = val}
|
86
90
|
when :monitor, :monitor_stable
|
87
91
|
optsParser.on("-w", "--watch <PERIOD>", Integer,
|
88
|
-
"Watch and refresh
|
92
|
+
"Watch and refresh CI status every <PERIOD>.") {
|
89
93
|
|val| opts[:watch] = val}
|
90
94
|
when :push
|
91
95
|
optsParser.banner += "[-f]"
|
@@ -93,8 +97,8 @@ module GitMaintain
|
|
93
97
|
|val| opts[:push_force] = val}
|
94
98
|
when :push_stable
|
95
99
|
optsParser.banner += "[-T]"
|
96
|
-
optsParser.on("-T", "--no-
|
97
|
-
|val| opts[:
|
100
|
+
optsParser.on("-T", "--no-ci", "Ignore CI build status and push anyway.") {
|
101
|
+
|val| opts[:no_ci] = true}
|
98
102
|
optsParser.on("-c", "--check", "Check if there is something to be pushed.") {
|
99
103
|
|val| opts[:check_only] = true}
|
100
104
|
when :steal
|
@@ -112,18 +116,19 @@ module GitMaintain
|
|
112
116
|
raise "Action #{opts[:action]} can only be done on 'master' suffixed branches"
|
113
117
|
end
|
114
118
|
end
|
115
|
-
if opts[:action] == :delete then
|
119
|
+
if opts[:action] == :delete && opts[:delete_remote] != true then
|
116
120
|
if opts[:br_suff] == "master" then
|
117
121
|
raise "Action #{opts[:action]} can NOT be done on 'master' suffixed branches"
|
118
122
|
end
|
119
123
|
end
|
124
|
+
opts[:version] = [ /.*/ ] if opts[:version].length == 0
|
120
125
|
end
|
121
126
|
|
122
127
|
def self.execAction(opts, action)
|
123
128
|
repo = Repo::load()
|
124
|
-
|
129
|
+
ci = CI::load(repo)
|
125
130
|
opts[:repo] = repo
|
126
|
-
opts[:
|
131
|
+
opts[:ci] = ci
|
127
132
|
brClass = GitMaintain::getClass(self, repo.name)
|
128
133
|
|
129
134
|
if NO_FETCH_ACTIONS.index(action) == nil && opts[:fetch] != false then
|
@@ -140,7 +145,7 @@ module GitMaintain
|
|
140
145
|
unfilteredList = repo.getBranchList(opts[:br_suff])
|
141
146
|
end
|
142
147
|
branchList = unfilteredList.map(){|br|
|
143
|
-
branch = Branch::load(repo, br,
|
148
|
+
branch = Branch::load(repo, br, ci, opts[:br_suff])
|
144
149
|
case branch.is_targetted?(opts)
|
145
150
|
when :too_old
|
146
151
|
GitMaintain::log(:VERBOSE, "Skipping older v#{branch.version}")
|
@@ -153,7 +158,7 @@ module GitMaintain
|
|
153
158
|
branch
|
154
159
|
}.compact()
|
155
160
|
else
|
156
|
-
branchList = [ Branch::load(repo, opts[:manual_branch],
|
161
|
+
branchList = [ Branch::load(repo, opts[:manual_branch], ci, opts[:br_suff]) ]
|
157
162
|
end
|
158
163
|
|
159
164
|
loop do
|
@@ -178,15 +183,15 @@ module GitMaintain
|
|
178
183
|
|
179
184
|
break if opts[:watch] == false
|
180
185
|
sleep(opts[:watch])
|
181
|
-
|
186
|
+
ci.emptyCache()
|
182
187
|
end
|
183
188
|
end
|
184
189
|
|
185
|
-
def initialize(repo, version,
|
190
|
+
def initialize(repo, version, ci, branch_suff)
|
186
191
|
GitMaintain::checkDirectConstructor(self.class)
|
187
192
|
|
188
193
|
@repo = repo
|
189
|
-
@
|
194
|
+
@ci = ci
|
190
195
|
@version = version
|
191
196
|
@branch_suff = branch_suff
|
192
197
|
|
@@ -223,10 +228,10 @@ module GitMaintain
|
|
223
228
|
if @version.to_i < opts[:base_ver] then
|
224
229
|
return :too_old
|
225
230
|
end
|
226
|
-
|
227
|
-
return
|
228
|
-
|
229
|
-
return
|
231
|
+
opts[:version].each() {|regexp|
|
232
|
+
return true if @version =~ regexp
|
233
|
+
}
|
234
|
+
return :no_match
|
230
235
|
end
|
231
236
|
|
232
237
|
# Checkout the repo to the given branch
|
@@ -271,7 +276,7 @@ module GitMaintain
|
|
271
276
|
end
|
272
277
|
|
273
278
|
master_sha=@repo.runGit("rev-parse origin/master")
|
274
|
-
res = steal_all(opts, "#{base_ref}..#{master_sha}")
|
279
|
+
res = steal_all(opts, "#{base_ref}..#{master_sha}", true)
|
275
280
|
|
276
281
|
# If we picked all the commits (or nothing happened)
|
277
282
|
# Mark the current master as the last checked point so we
|
@@ -345,22 +350,22 @@ module GitMaintain
|
|
345
350
|
"#{opts[:repo].valid_repo} #{branches.join(" ")}")
|
346
351
|
end
|
347
352
|
|
348
|
-
# Monitor the build status on
|
353
|
+
# Monitor the build status on CI
|
349
354
|
def monitor(opts)
|
350
|
-
st = @
|
355
|
+
st = @ci.getValidState(self, @head)
|
351
356
|
suff=""
|
352
357
|
case st
|
353
358
|
when "started"
|
354
|
-
suff= " started at #{@
|
359
|
+
suff= " started at #{@ci.getValidTS(self, @head)}"
|
355
360
|
end
|
356
361
|
log(:INFO, "Status for v#{@version}: " + st + suff)
|
357
|
-
if (
|
362
|
+
if @ci.isErrored(self, st) && opts[:watch] == false
|
358
363
|
rep = "y"
|
359
364
|
suff=""
|
360
365
|
while rep == "y"
|
361
366
|
rep = GitMaintain::confirm(opts, "see the build log#{suff}")
|
362
367
|
if rep == "y" then
|
363
|
-
log = @
|
368
|
+
log = @ci.getValidLog(self, @head)
|
364
369
|
tmp = `mktemp`.chomp()
|
365
370
|
tmpfile = File.open(tmp, "w+")
|
366
371
|
tmpfile.puts(log)
|
@@ -375,9 +380,9 @@ module GitMaintain
|
|
375
380
|
|
376
381
|
# Push branch to the stable repo
|
377
382
|
def push_stable(opts)
|
378
|
-
if (opts[:
|
379
|
-
@
|
380
|
-
log(:WARNING, "Build is not passed on
|
383
|
+
if (opts[:no_ci] != true && @NO_CI != true) &&
|
384
|
+
@ci.checkValidState(self, @head) != true then
|
385
|
+
log(:WARNING, "Build is not passed on CI. Skipping push to stable")
|
381
386
|
return
|
382
387
|
end
|
383
388
|
|
@@ -408,13 +413,13 @@ module GitMaintain
|
|
408
413
|
return if branches.length == 0
|
409
414
|
opts[:repo].runGit("push #{opts[:repo].stable_repo} #{branches.join(" ")}")
|
410
415
|
end
|
411
|
-
# Monitor the build status of the stable branch on
|
416
|
+
# Monitor the build status of the stable branch on CI
|
412
417
|
def monitor_stable(opts)
|
413
|
-
st = @
|
418
|
+
st = @ci.getStableState(self, @stable_head)
|
414
419
|
suff=""
|
415
420
|
case st
|
416
421
|
when "started"
|
417
|
-
suff= " started at #{@
|
422
|
+
suff= " started at #{@ci.getStableTS(self, @stable_head)}"
|
418
423
|
end
|
419
424
|
log(:INFO, "Status for v#{@version}: " + st + suff)
|
420
425
|
end
|
@@ -446,14 +451,36 @@ module GitMaintain
|
|
446
451
|
end
|
447
452
|
|
448
453
|
def delete(opts)
|
449
|
-
|
454
|
+
if opts[:delete_remote] == true then
|
455
|
+
msg = "delete remote branch #{@repo.valid_repo}/#{@local_branch}"
|
456
|
+
else
|
457
|
+
msg = "delete branch #{@local_branch}"
|
458
|
+
end
|
459
|
+
rep = GitMaintain::confirm(opts, msg)
|
450
460
|
if rep == "y" then
|
451
|
-
|
461
|
+
return @local_branch
|
452
462
|
else
|
453
463
|
log(:INFO, "Skipping deletion")
|
454
464
|
return
|
455
465
|
end
|
456
466
|
end
|
467
|
+
def self.delete_epilogue(opts, branches)
|
468
|
+
# Compact to remove empty entries
|
469
|
+
branches.compact!()
|
470
|
+
|
471
|
+
return if branches.length == 0
|
472
|
+
puts "Deleting #{opts[:delete_remote] == true ? "remote" : "local"} branches: #{branches.join(" ")}"
|
473
|
+
rep = GitMaintain::confirm(opts, "continue")
|
474
|
+
if rep != "y" then
|
475
|
+
log(:INFO, "Cancelling")
|
476
|
+
return
|
477
|
+
end
|
478
|
+
if opts[:delete_remote] == true then
|
479
|
+
opts[:repo].runGit("push #{opts[:repo].valid_repo} #{branches.map(){|x| ":" + x}.join(" ")}")
|
480
|
+
else
|
481
|
+
opts[:repo].runGit("branch -D #{branches.join(" ")}")
|
482
|
+
end
|
483
|
+
end
|
457
484
|
|
458
485
|
private
|
459
486
|
def add_blacklist(commit)
|
@@ -532,13 +559,15 @@ module GitMaintain
|
|
532
559
|
end
|
533
560
|
|
534
561
|
# Let's see if there's a version tag in this commit
|
535
|
-
full=@repo.runGit("show #{commit} | grep -i 'stable@'").gsub(/.*
|
562
|
+
full=@repo.runGit("show #{commit} | grep -i 'stable@'").gsub(/.* #?/, "")
|
536
563
|
|
537
564
|
# Sanity check our extraction
|
538
565
|
if full =~ /stable/ then
|
539
566
|
return false
|
540
567
|
end
|
541
568
|
|
569
|
+
full = @repo.runGit("rev-parse #{full}^{commit}")
|
570
|
+
|
542
571
|
# Make sure our branch contains this version
|
543
572
|
if @repo.runGit("merge-base #{@head} #{full}") == full then
|
544
573
|
return true
|
@@ -607,17 +636,23 @@ module GitMaintain
|
|
607
636
|
return do_cp
|
608
637
|
end
|
609
638
|
|
610
|
-
def steal_one(opts, commit)
|
611
|
-
subj=@repo.getCommitSubj(commit)
|
612
|
-
subj.gsub!(/"/, '\"')
|
639
|
+
def steal_one(opts, commit, mainline=false)
|
613
640
|
msg=''
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
641
|
+
orig_cmt=commit
|
642
|
+
|
643
|
+
if mainline == false then
|
644
|
+
subj=@repo.getCommitSubj(commit)
|
645
|
+
subj.gsub!(/"/, '\"')
|
646
|
+
# Let's grab the mainline commit id, this is useful if the version tag
|
647
|
+
# doesn't exist in the commit we're looking at but exists upstream.
|
648
|
+
orig_cmt=@repo.runGit("log --no-merges --format=\"%H\" -F --grep \"#{subj}\" " +
|
649
|
+
"#{@stable_base}..origin/master | tail -n1")
|
650
|
+
|
651
|
+
if orig_cmt == "" then
|
652
|
+
log(:WARNING, "Could not find commit #{commit} in mainline")
|
653
|
+
end
|
654
|
+
end
|
655
|
+
# If the commit doesn't apply for us, skip it
|
621
656
|
if is_relevant?(orig_cmt) != true
|
622
657
|
return true
|
623
658
|
end
|
@@ -663,10 +698,10 @@ module GitMaintain
|
|
663
698
|
end
|
664
699
|
end
|
665
700
|
|
666
|
-
def steal_all(opts, range)
|
701
|
+
def steal_all(opts, range, mainline = false)
|
667
702
|
res = true
|
668
703
|
@repo.runGit("log --no-merges --format=\"%H\" #{range} | tac").split("\n").each(){|commit|
|
669
|
-
res &= steal_one(opts, commit)
|
704
|
+
res &= steal_one(opts, commit, mainline)
|
670
705
|
}
|
671
706
|
return res
|
672
707
|
end
|