git-process-lib 2.0.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 +123 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +57 -0
- data/LICENSE +193 -0
- data/README.md +342 -0
- data/Rakefile +32 -0
- data/bin/git-new-fb +39 -0
- data/bin/git-pull-request +63 -0
- data/bin/git-sync +38 -0
- data/bin/git-to-master +44 -0
- data/docs/git-new-fb.1.adoc +83 -0
- data/docs/git-process.1.adoc +227 -0
- data/docs/git-pull-request.1.adoc +166 -0
- data/docs/git-sync.1.adoc +120 -0
- data/docs/git-to-master.1.adoc +172 -0
- data/git-new-fb.gemspec +20 -0
- data/git-process-lib.gemspec +25 -0
- data/git-process.gemspec +22 -0
- data/git-pull-request.gemspec +20 -0
- data/git-sync.gemspec +20 -0
- data/git-to-master.gemspec +20 -0
- data/lib/git-process/abstract_error_builder.rb +53 -0
- data/lib/git-process/changed_file_helper.rb +115 -0
- data/lib/git-process/git_abstract_merge_error_builder.rb +130 -0
- data/lib/git-process/git_branch.rb +105 -0
- data/lib/git-process/git_branches.rb +81 -0
- data/lib/git-process/git_config.rb +135 -0
- data/lib/git-process/git_lib.rb +646 -0
- data/lib/git-process/git_logger.rb +84 -0
- data/lib/git-process/git_merge_error.rb +28 -0
- data/lib/git-process/git_process.rb +159 -0
- data/lib/git-process/git_process_error.rb +18 -0
- data/lib/git-process/git_process_options.rb +101 -0
- data/lib/git-process/git_rebase_error.rb +30 -0
- data/lib/git-process/git_remote.rb +222 -0
- data/lib/git-process/git_status.rb +108 -0
- data/lib/git-process/github_configuration.rb +298 -0
- data/lib/git-process/github_pull_request.rb +165 -0
- data/lib/git-process/new_fb.rb +49 -0
- data/lib/git-process/parked_changes_error.rb +41 -0
- data/lib/git-process/pull_request.rb +136 -0
- data/lib/git-process/pull_request_error.rb +25 -0
- data/lib/git-process/rebase_to_master.rb +148 -0
- data/lib/git-process/sync_process.rb +55 -0
- data/lib/git-process/syncer.rb +157 -0
- data/lib/git-process/uncommitted_changes_error.rb +23 -0
- data/lib/git-process/version.rb +22 -0
- data/local-build.rb +24 -0
- data/spec/FileHelpers.rb +19 -0
- data/spec/GitRepoHelper.rb +123 -0
- data/spec/changed_file_helper_spec.rb +127 -0
- data/spec/git_abstract_merge_error_builder_spec.rb +64 -0
- data/spec/git_branch_spec.rb +123 -0
- data/spec/git_config_spec.rb +45 -0
- data/spec/git_lib_spec.rb +176 -0
- data/spec/git_logger_spec.rb +66 -0
- data/spec/git_process_spec.rb +208 -0
- data/spec/git_remote_spec.rb +227 -0
- data/spec/git_status_spec.rb +122 -0
- data/spec/github_configuration_spec.rb +152 -0
- data/spec/github_pull_request_spec.rb +117 -0
- data/spec/github_test_helper.rb +49 -0
- data/spec/new_fb_spec.rb +126 -0
- data/spec/pull_request_helper.rb +94 -0
- data/spec/pull_request_spec.rb +137 -0
- data/spec/rebase_to_master_spec.rb +362 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/sync_spec.rb +1474 -0
- metadata +249 -0
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib')
|
2
|
+
|
3
|
+
require 'GitRepoHelper'
|
4
|
+
require 'pull_request_helper'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
8
|
+
|
9
|
+
config.include GitRepoHelper, :git_repo_helper
|
10
|
+
|
11
|
+
config.before(:each, :git_repo_helper) do
|
12
|
+
create_files(%w(.gitignore))
|
13
|
+
gitlib.commit('initial')
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
config.after(:each, :git_repo_helper) do
|
18
|
+
rm_rf(gitlib.workdir)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/spec/sync_spec.rb
ADDED
@@ -0,0 +1,1474 @@
|
|
1
|
+
require 'git-process/sync_process'
|
2
|
+
require 'GitRepoHelper'
|
3
|
+
require 'rugged'
|
4
|
+
|
5
|
+
|
6
|
+
describe Sync do
|
7
|
+
include GitRepoHelper
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
create_files(%w(.gitignore))
|
11
|
+
gitlib.commit('initial')
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
after(:each) do
|
16
|
+
rm_rf(gitlib.workdir)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def log_level
|
21
|
+
Logger::ERROR
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def create_process(base = gitlib, opts = {})
|
26
|
+
GitProc::Sync.new(base, opts.merge({:rebase => false, :force => false}))
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def verify_start_state
|
31
|
+
# meant to overridden
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
it 'should work when pushing with fast-forward' do
|
36
|
+
Given do
|
37
|
+
origin 'fb', :new_branch => 'master'
|
38
|
+
create_commit :b
|
39
|
+
local 'fb', :new_branch => 'origin/fb'
|
40
|
+
create_commit :c
|
41
|
+
end
|
42
|
+
|
43
|
+
when_sync_is_run
|
44
|
+
|
45
|
+
Then do
|
46
|
+
local_and_remote_are_same
|
47
|
+
l_sha.should == @local.sha('origin/fb')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
it 'should work with a different remote server name' do
|
53
|
+
Given do
|
54
|
+
origin 'fb', :new_branch => 'master'
|
55
|
+
create_commit :b
|
56
|
+
local 'fb', :new_branch => 'a_remote/fb', :remote_name => 'a_remote'
|
57
|
+
create_commit :c
|
58
|
+
end
|
59
|
+
|
60
|
+
when_sync_is_run
|
61
|
+
|
62
|
+
Then do
|
63
|
+
local_and_remote_are_same
|
64
|
+
l_sha.should == @local.sha('a_remote/fb')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
describe 'when forcing the push with a merge' do
|
70
|
+
|
71
|
+
def create_process(gitlib, opts)
|
72
|
+
GitProc::Sync.new(gitlib, opts.merge({:rebase => false, :force => true}))
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
it 'should work when pushing with non-fast-forward' do
|
77
|
+
change_file_and_commit('a', '')
|
78
|
+
|
79
|
+
gitlib.branch('fb', :base_branch => 'master')
|
80
|
+
|
81
|
+
clone_repo('fb') do |gl|
|
82
|
+
gitlib.checkout('fb') do
|
83
|
+
change_file_and_commit('a', 'hello', gitlib)
|
84
|
+
end
|
85
|
+
|
86
|
+
GitProc::Sync.new(gl, :rebase => false, :force => true, :log_level => log_level).runner
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
describe 'when merging' do
|
94
|
+
|
95
|
+
def create_process(gitlib, opts = {})
|
96
|
+
GitProc::Sync.new(gitlib, opts.merge({:rebase => true, :force => false}))
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
context 'piece by piece' do
|
101
|
+
it 'should do the same as rebase, but with merge - HOLDER'
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
describe 'when rebasing' do
|
108
|
+
|
109
|
+
def create_process(gitlib, opts = {})
|
110
|
+
GitProc::Sync.new(gitlib, opts.merge({:rebase => true, :force => false}))
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
context 'piece by piece' do
|
115
|
+
|
116
|
+
#
|
117
|
+
# Legend for the symbols below:
|
118
|
+
# i - integration branch (i.e., 'origin/master')
|
119
|
+
# l - local/working feature branch (i.e., 'fb')
|
120
|
+
# r - remote feature branch (i.e., 'origin/fb')
|
121
|
+
#
|
122
|
+
|
123
|
+
before(:each) do
|
124
|
+
@origin = gitlib
|
125
|
+
@origin.config['receive.denyCurrentBranch'] = 'ignore'
|
126
|
+
|
127
|
+
@a_sha = rcreate_commit :origin, 'HEAD', :a
|
128
|
+
|
129
|
+
@local = clone_repo('master', 'origin')
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
after(:each) do
|
134
|
+
rm_rf(@origin.workdir)
|
135
|
+
rm_rf(@local.workdir)
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
# i
|
140
|
+
# /
|
141
|
+
# - A - C
|
142
|
+
# \
|
143
|
+
# B
|
144
|
+
# \
|
145
|
+
# l,r
|
146
|
+
#
|
147
|
+
# Steps to get to this state:
|
148
|
+
# 1. Changes have been applied to the integration branch
|
149
|
+
# 2. No work has happened on the feature branch since the last `sync`
|
150
|
+
#
|
151
|
+
describe 'if local/remote match' do
|
152
|
+
|
153
|
+
def verify_start_state
|
154
|
+
l_sha.should == @b_sha
|
155
|
+
r_sha.should == @b_sha
|
156
|
+
i_sha.should == @c_sha
|
157
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
158
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
# i
|
163
|
+
# /
|
164
|
+
# - A - C - B1
|
165
|
+
# /
|
166
|
+
# l,r
|
167
|
+
it 'should work if no conflict' do
|
168
|
+
Given do
|
169
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
170
|
+
rfetch local_repo, 'origin'
|
171
|
+
local_repo.create_branch('fb', 'origin/fb')
|
172
|
+
@local.write_sync_control_file('fb')
|
173
|
+
rcreate_commit :origin, 'master', :c
|
174
|
+
end
|
175
|
+
|
176
|
+
when_sync_is_run
|
177
|
+
|
178
|
+
Then do
|
179
|
+
local_and_remote_are_same
|
180
|
+
parent(l_sha).should == @c_sha
|
181
|
+
check_file_content :b
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
# i
|
187
|
+
# /
|
188
|
+
# - A - C - XX
|
189
|
+
# \ /
|
190
|
+
# B l
|
191
|
+
# \
|
192
|
+
# r
|
193
|
+
it 'should raise an error if there is a conflict' do
|
194
|
+
Given do
|
195
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b, :file => 'a'
|
196
|
+
rfetch local_repo, 'origin'
|
197
|
+
local_repo.create_branch('fb', 'origin/fb')
|
198
|
+
@local.write_sync_control_file('fb')
|
199
|
+
rcreate_commit :origin, 'master', :c, :file => 'a'
|
200
|
+
end
|
201
|
+
|
202
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
# i
|
208
|
+
# /
|
209
|
+
# - A - C
|
210
|
+
# \
|
211
|
+
# B - D
|
212
|
+
# \ \
|
213
|
+
# r l
|
214
|
+
#
|
215
|
+
# Steps to get to this state:
|
216
|
+
# 1. Changes have been applied to the integration branch
|
217
|
+
# 2. Work has happened locally only on the feature branch since the last `sync`
|
218
|
+
#
|
219
|
+
describe 'if local is a fast-forward of remote' do
|
220
|
+
|
221
|
+
def verify_start_state
|
222
|
+
l_sha.should == @d_sha
|
223
|
+
r_sha.should == @b_sha
|
224
|
+
i_sha.should == @c_sha
|
225
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
226
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
227
|
+
treeish(local_repo, "#{@d_sha}~1").should == @b_sha
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
# i
|
232
|
+
# /
|
233
|
+
# - A - C - B1 - D1
|
234
|
+
# /
|
235
|
+
# l,r
|
236
|
+
it 'should work if no conflict' do
|
237
|
+
Given do
|
238
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
239
|
+
rfetch local_repo, 'origin'
|
240
|
+
local_repo.create_branch('fb', 'origin/fb')
|
241
|
+
@local.write_sync_control_file('fb')
|
242
|
+
rcreate_commit :local, 'fb', :d
|
243
|
+
rcreate_commit :origin, 'master', :c
|
244
|
+
end
|
245
|
+
|
246
|
+
when_sync_is_run
|
247
|
+
|
248
|
+
Then do
|
249
|
+
local_and_remote_are_same
|
250
|
+
@local.sha("#{l_sha}~2").should == @c_sha
|
251
|
+
check_file_content :b
|
252
|
+
check_file_content :d
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
# i
|
258
|
+
# /
|
259
|
+
# - A - C - XX
|
260
|
+
# \ \
|
261
|
+
# B - D l
|
262
|
+
# \ \
|
263
|
+
# r ??
|
264
|
+
it 'should raise an error if there is a conflict' do
|
265
|
+
Given do
|
266
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b, :file => 'a'
|
267
|
+
rfetch local_repo, 'origin'
|
268
|
+
local_repo.create_branch('fb', 'origin/fb')
|
269
|
+
@local.write_sync_control_file('fb')
|
270
|
+
rcreate_commit :local, 'fb', :d
|
271
|
+
rcreate_commit :origin, 'master', :c, :file => 'a'
|
272
|
+
end
|
273
|
+
|
274
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
# i l
|
281
|
+
# / \
|
282
|
+
# - A - C - B1 - D
|
283
|
+
# \
|
284
|
+
# B
|
285
|
+
# \
|
286
|
+
# r
|
287
|
+
#
|
288
|
+
# Steps to get to this state:
|
289
|
+
# 1. Changes have been applied to the integration branch
|
290
|
+
# 2. The local feature branch is manually rebased with integration
|
291
|
+
# 2. Work has happened locally only on the feature branch since the last `sync`
|
292
|
+
#
|
293
|
+
describe 'if local has already been rebased onto integration' do
|
294
|
+
|
295
|
+
def verify_start_state
|
296
|
+
l_sha.should == @d_sha
|
297
|
+
r_sha.should == @b_sha
|
298
|
+
i_sha.should == @c_sha
|
299
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
300
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
301
|
+
treeish(local_repo, "#{@b1_sha}~1").should == @c_sha
|
302
|
+
treeish(local_repo, "#{@d_sha}~2").should == @c_sha
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
# i
|
307
|
+
# /
|
308
|
+
# - A - C - B1 - D
|
309
|
+
# /
|
310
|
+
# l,r
|
311
|
+
it 'should work' do
|
312
|
+
Given do
|
313
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
314
|
+
rcreate_commit :origin, 'master', :c
|
315
|
+
rfetch local_repo, 'origin'
|
316
|
+
rcreate_commit_on_new_branch :local, 'fb', 'origin/master', :b1, :file => 'b'
|
317
|
+
rcreate_commit :local, 'fb', :d
|
318
|
+
end
|
319
|
+
|
320
|
+
when_sync_is_run
|
321
|
+
|
322
|
+
Then do
|
323
|
+
local_and_remote_are_same
|
324
|
+
treeish(local_repo, "#{l_sha}~2").should == @c_sha
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|
329
|
+
|
330
|
+
|
331
|
+
# i r
|
332
|
+
# / /
|
333
|
+
# - A - C - B1
|
334
|
+
# \
|
335
|
+
# B - D
|
336
|
+
# \
|
337
|
+
# l
|
338
|
+
#
|
339
|
+
# Steps to get to this state:
|
340
|
+
# 1. Changes have been applied to the integration branch
|
341
|
+
# 2. The remote feature branch is rebased with integration, but no new work
|
342
|
+
# 2. Work has happened locally on the feature branch
|
343
|
+
#
|
344
|
+
describe 'if remote has already been rebased onto integration' do
|
345
|
+
|
346
|
+
def verify_start_state
|
347
|
+
l_sha.should == @d_sha
|
348
|
+
r_sha.should == @b1_sha
|
349
|
+
i_sha.should == @c_sha
|
350
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
351
|
+
treeish(local_repo, "#{@b_sha}~1").should == @a_sha
|
352
|
+
treeish(origin_repo, "#{@b1_sha}~1").should == @c_sha
|
353
|
+
treeish(local_repo, "#{@d_sha}~1").should == @b_sha
|
354
|
+
end
|
355
|
+
|
356
|
+
|
357
|
+
# i
|
358
|
+
# /
|
359
|
+
# - A - C - B1 - D1
|
360
|
+
# /
|
361
|
+
# l,r
|
362
|
+
it 'should work' do
|
363
|
+
Given do
|
364
|
+
rcreate_commit_on_new_branch :local, 'fb', 'origin/master', :b
|
365
|
+
@local.write_sync_control_file('fb')
|
366
|
+
rcreate_commit :local, 'fb', :d
|
367
|
+
rcreate_commit :origin, 'master', :c
|
368
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b1, :file => 'b'
|
369
|
+
end
|
370
|
+
|
371
|
+
when_sync_is_run
|
372
|
+
|
373
|
+
Then do
|
374
|
+
local_and_remote_are_same
|
375
|
+
l_sha.should_not == @d_sha
|
376
|
+
treeish(local_repo, "#{l_sha}~1").should == @b1_sha
|
377
|
+
treeish(local_repo, "#{l_sha}~2").should == @c_sha
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
|
382
|
+
# i r
|
383
|
+
# / /
|
384
|
+
# - A - C - B1 - XX
|
385
|
+
# \ /
|
386
|
+
# B - D l
|
387
|
+
# \
|
388
|
+
# ??
|
389
|
+
it 'should raise an error if there is a conflict' do
|
390
|
+
Given do
|
391
|
+
rcreate_commit_on_new_branch :local, 'fb', 'origin/master', :b
|
392
|
+
rcreate_commit :local, 'fb', :d, :file => 'a'
|
393
|
+
rcreate_commit :origin, 'master', :c, :file => 'a'
|
394
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b1, :file => 'b'
|
395
|
+
end
|
396
|
+
|
397
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
398
|
+
end
|
399
|
+
|
400
|
+
end
|
401
|
+
|
402
|
+
|
403
|
+
# i r
|
404
|
+
# / \
|
405
|
+
# - A - C - B1 - D
|
406
|
+
# \
|
407
|
+
# B
|
408
|
+
# \
|
409
|
+
# l
|
410
|
+
#
|
411
|
+
# Steps to get to this state:
|
412
|
+
# 1. Changes have been applied to the integration branch
|
413
|
+
# 2. The remote feature branch is rebased with integration, but with new work
|
414
|
+
# 2. Work has not happened locally on the feature branch
|
415
|
+
#
|
416
|
+
describe 'if remote is ahead of local' do
|
417
|
+
|
418
|
+
def verify_start_state
|
419
|
+
l_sha.should == @b_sha
|
420
|
+
r_sha.should == @d_sha
|
421
|
+
i_sha.should == @c_sha
|
422
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
423
|
+
treeish(local_repo, "#{@b_sha}~1").should == @a_sha
|
424
|
+
treeish(origin_repo, "#{@b1_sha}~1").should == @c_sha
|
425
|
+
treeish(origin_repo, "#{@d_sha}~1").should == @b1_sha
|
426
|
+
end
|
427
|
+
|
428
|
+
|
429
|
+
# i
|
430
|
+
# /
|
431
|
+
# - A - C - B1 - D
|
432
|
+
# /
|
433
|
+
# l,r
|
434
|
+
it 'should work' do
|
435
|
+
Given do
|
436
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
437
|
+
rfetch local_repo, 'origin'
|
438
|
+
local_repo.create_branch('fb', 'origin/fb')
|
439
|
+
@local.write_sync_control_file('fb')
|
440
|
+
rcreate_commit :origin, 'master', :c
|
441
|
+
rcreate_commit :origin, 'fb', :b1, :file => 'b', :parents => [@c_sha]
|
442
|
+
rcreate_commit :origin, 'fb', :d
|
443
|
+
end
|
444
|
+
|
445
|
+
when_sync_is_run
|
446
|
+
|
447
|
+
Then do
|
448
|
+
local_and_remote_are_same
|
449
|
+
l_sha.should == @d_sha
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
|
454
|
+
# i
|
455
|
+
# /
|
456
|
+
# - A - C - B1 - D
|
457
|
+
# /
|
458
|
+
# l,r
|
459
|
+
it 'should work without a control file' do
|
460
|
+
Given do
|
461
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
462
|
+
rfetch local_repo, 'origin'
|
463
|
+
local_repo.create_branch('fb', 'origin/fb')
|
464
|
+
rcreate_commit :origin, 'master', :c
|
465
|
+
rcreate_commit :origin, 'fb', :b1, :file => 'b', :parents => [@c_sha]
|
466
|
+
rcreate_commit :origin, 'fb', :d
|
467
|
+
end
|
468
|
+
|
469
|
+
when_sync_is_run
|
470
|
+
|
471
|
+
Then do
|
472
|
+
local_and_remote_are_same
|
473
|
+
l_sha.should == @d_sha
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
end
|
478
|
+
|
479
|
+
|
480
|
+
# i
|
481
|
+
# /
|
482
|
+
# - A - C
|
483
|
+
# \
|
484
|
+
# B - D
|
485
|
+
# \ \
|
486
|
+
# \ l
|
487
|
+
# E
|
488
|
+
# \
|
489
|
+
# r
|
490
|
+
#
|
491
|
+
# Steps to get to this state:
|
492
|
+
# 1. Changes have been applied to the integration branch
|
493
|
+
# 2. Work has happened locally
|
494
|
+
# 3. Work has happened remotely
|
495
|
+
#
|
496
|
+
describe 'if local and remote both have work done on them, and remote has not been rebased' do
|
497
|
+
|
498
|
+
def verify_start_state
|
499
|
+
l_sha.should == @d_sha
|
500
|
+
r_sha.should == @e_sha
|
501
|
+
i_sha.should == @c_sha
|
502
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
503
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
504
|
+
treeish(local_repo, "#{@d_sha}~1").should == @b_sha
|
505
|
+
treeish(origin_repo, "#{@e_sha}~1").should == @b_sha
|
506
|
+
end
|
507
|
+
|
508
|
+
|
509
|
+
# i l,r
|
510
|
+
# / \
|
511
|
+
# - A - C - B1 - E1 - D1
|
512
|
+
it 'should work if no conflict' do
|
513
|
+
Given do
|
514
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
515
|
+
rfetch local_repo, 'origin'
|
516
|
+
local_repo.create_branch('fb', 'origin/fb')
|
517
|
+
@local.write_sync_control_file('fb')
|
518
|
+
rcreate_commit :local, 'fb', :d
|
519
|
+
rcreate_commit :origin, 'master', :c
|
520
|
+
rcreate_commit :origin, 'fb', :e
|
521
|
+
end
|
522
|
+
|
523
|
+
when_sync_is_run
|
524
|
+
|
525
|
+
Then do
|
526
|
+
local_and_remote_are_same
|
527
|
+
treeish(origin_repo, "#{l_sha}~3").should == @c_sha
|
528
|
+
check_file_content :b
|
529
|
+
check_file_content :d
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
|
534
|
+
# i l
|
535
|
+
# / /
|
536
|
+
# - A - C - XX
|
537
|
+
# \
|
538
|
+
# B - D
|
539
|
+
# \ \
|
540
|
+
# \ ??
|
541
|
+
# E
|
542
|
+
# \
|
543
|
+
# r
|
544
|
+
it 'should raise an error if conflict applying B' do
|
545
|
+
Given do
|
546
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b, :file => 'a'
|
547
|
+
rfetch local_repo, 'origin'
|
548
|
+
local_repo.create_branch('fb', 'origin/fb')
|
549
|
+
@local.write_sync_control_file('fb')
|
550
|
+
rcreate_commit :local, 'fb', :d
|
551
|
+
rcreate_commit :origin, 'master', :c, :file => 'a'
|
552
|
+
rcreate_commit :origin, 'fb', :e
|
553
|
+
end
|
554
|
+
|
555
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
556
|
+
end
|
557
|
+
|
558
|
+
|
559
|
+
# i l
|
560
|
+
# / \
|
561
|
+
# - A - C - B1 - XX
|
562
|
+
# \
|
563
|
+
# B - D
|
564
|
+
# \ \
|
565
|
+
# \ ??
|
566
|
+
# E
|
567
|
+
# \
|
568
|
+
# r
|
569
|
+
it 'should raise an error if there is a conflict applying remote' do
|
570
|
+
Given do
|
571
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
572
|
+
rfetch local_repo, 'origin'
|
573
|
+
local_repo.create_branch('fb', 'origin/fb')
|
574
|
+
@local.write_sync_control_file('fb')
|
575
|
+
rcreate_commit :local, 'fb', :d
|
576
|
+
rcreate_commit :origin, 'master', :c, :file => 'a'
|
577
|
+
rcreate_commit :origin, 'fb', :e, :file => 'a'
|
578
|
+
end
|
579
|
+
|
580
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
581
|
+
end
|
582
|
+
|
583
|
+
|
584
|
+
# i l
|
585
|
+
# / \
|
586
|
+
# - A - C - B1 - E1 - XX
|
587
|
+
# \
|
588
|
+
# B - D
|
589
|
+
# \ \
|
590
|
+
# \ ??
|
591
|
+
# E
|
592
|
+
# \
|
593
|
+
# r
|
594
|
+
it 'should raise an error if conflict applying local' do
|
595
|
+
Given do
|
596
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
597
|
+
rfetch local_repo, 'origin'
|
598
|
+
local_repo.create_branch('fb', 'origin/fb')
|
599
|
+
@local.write_sync_control_file('fb')
|
600
|
+
rcreate_commit :local, 'fb', :d, :file => 'a'
|
601
|
+
rcreate_commit :origin, 'master', :c, :file => 'a'
|
602
|
+
rcreate_commit :origin, 'fb', :e
|
603
|
+
end
|
604
|
+
|
605
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
606
|
+
end
|
607
|
+
|
608
|
+
end
|
609
|
+
|
610
|
+
|
611
|
+
# i l
|
612
|
+
# / /
|
613
|
+
# - A - C - D
|
614
|
+
# \
|
615
|
+
# B
|
616
|
+
# \
|
617
|
+
# r
|
618
|
+
#
|
619
|
+
# Steps to get to this state:
|
620
|
+
# 1. Changes have been applied to the integration branch
|
621
|
+
# 2. Nothing has changed on the remote since the last sync
|
622
|
+
# 3. Work has happened locally on the feature branch, and it is no longer a "simple" addition to the remote
|
623
|
+
#
|
624
|
+
describe 'if local is based on integration but not a "simple" version of remote' do
|
625
|
+
|
626
|
+
def verify_start_state
|
627
|
+
l_sha.should == @d_sha
|
628
|
+
r_sha.should == @b_sha
|
629
|
+
i_sha.should == @c_sha
|
630
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
631
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
632
|
+
treeish(local_repo, "#{@d_sha}~1").should == @c_sha
|
633
|
+
end
|
634
|
+
|
635
|
+
|
636
|
+
# i
|
637
|
+
# /
|
638
|
+
# - A - C - D
|
639
|
+
# /
|
640
|
+
# l,r
|
641
|
+
it 'should override remote branch' do
|
642
|
+
Given do
|
643
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
644
|
+
rcreate_commit :origin, 'master', :c
|
645
|
+
rfetch local_repo, 'origin'
|
646
|
+
local_repo.create_branch('fb', 'origin/fb')
|
647
|
+
@local.write_sync_control_file('fb')
|
648
|
+
rcreate_commit :local, 'fb', :d, :parents => [@c_sha]
|
649
|
+
end
|
650
|
+
|
651
|
+
when_sync_is_run
|
652
|
+
|
653
|
+
Then do
|
654
|
+
local_and_remote_are_same
|
655
|
+
l_sha.should == @d_sha
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
end
|
660
|
+
|
661
|
+
|
662
|
+
# l
|
663
|
+
# /
|
664
|
+
# D
|
665
|
+
# /
|
666
|
+
# - A - C - E
|
667
|
+
# \ /
|
668
|
+
# B i
|
669
|
+
# \
|
670
|
+
# r
|
671
|
+
#
|
672
|
+
# Steps to get to this state:
|
673
|
+
# 1. Changes have been applied to the integration branch
|
674
|
+
# 2. Nothing has changed on the remote since the last sync
|
675
|
+
# 2. Work has happened locally based on a newer version of integration, and it is no longer
|
676
|
+
# a "simple" addition to the remote
|
677
|
+
#
|
678
|
+
describe 'if local is not based on integration and not a "simple" version of remote' do
|
679
|
+
|
680
|
+
def verify_start_state
|
681
|
+
l_sha.should == @d_sha
|
682
|
+
r_sha.should == @b_sha
|
683
|
+
i_sha.should == @e_sha
|
684
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
685
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
686
|
+
treeish(local_repo, "#{@d_sha}~1").should == @c_sha
|
687
|
+
treeish(origin_repo, "#{@e_sha}~1").should == @c_sha
|
688
|
+
end
|
689
|
+
|
690
|
+
|
691
|
+
# - A - C - E - D1
|
692
|
+
# / /
|
693
|
+
# i l,r
|
694
|
+
it 'should override remote branch' do
|
695
|
+
Given do
|
696
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
697
|
+
rcreate_commit :origin, 'master', :c
|
698
|
+
rfetch local_repo, 'origin'
|
699
|
+
local_repo.create_branch('fb', 'origin/fb')
|
700
|
+
@local.write_sync_control_file('fb')
|
701
|
+
rcreate_commit :local, 'fb', :d, :parents => [@c_sha]
|
702
|
+
rcreate_commit :origin, 'master', :e
|
703
|
+
end
|
704
|
+
|
705
|
+
when_sync_is_run
|
706
|
+
|
707
|
+
Then do
|
708
|
+
local_and_remote_are_same
|
709
|
+
treeish(origin_repo, "#{l_sha}~1").should == @e_sha
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
|
714
|
+
# ??
|
715
|
+
# /
|
716
|
+
# D
|
717
|
+
# /
|
718
|
+
# - A - C - E - XX
|
719
|
+
# \ / /
|
720
|
+
# B i l
|
721
|
+
# \
|
722
|
+
# r
|
723
|
+
it 'should raise an error with conflict on local content' do
|
724
|
+
Given do
|
725
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
726
|
+
rcreate_commit :origin, 'master', :c
|
727
|
+
rfetch local_repo, 'origin'
|
728
|
+
local_repo.create_branch('fb', 'origin/fb')
|
729
|
+
@local.write_sync_control_file('fb')
|
730
|
+
rcreate_commit :local, 'fb', :d, :parents => [@c_sha], :file => 'a'
|
731
|
+
rcreate_commit :origin, 'master', :e, :file => 'a'
|
732
|
+
end
|
733
|
+
|
734
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
735
|
+
end
|
736
|
+
|
737
|
+
end
|
738
|
+
|
739
|
+
|
740
|
+
# i r
|
741
|
+
# / \
|
742
|
+
# - A - C - B1 - E
|
743
|
+
# \
|
744
|
+
# B - D
|
745
|
+
# \
|
746
|
+
# l
|
747
|
+
#
|
748
|
+
# Steps to get to this state:
|
749
|
+
# 1. Changes have been applied to the integration branch
|
750
|
+
# 2. Work has happened locally based on an older version of integration
|
751
|
+
# 3. Work has happened remotely based on rebasing against integration
|
752
|
+
#
|
753
|
+
describe 'if local and remote both have work done on them, and remote has been rebased with integration' do
|
754
|
+
|
755
|
+
def verify_start_state
|
756
|
+
l_sha.should == @d_sha
|
757
|
+
r_sha.should == @e_sha
|
758
|
+
i_sha.should == @c_sha
|
759
|
+
treeish(local_repo, "#{@b_sha}~1").should == @a_sha
|
760
|
+
treeish(origin_repo, "#{@b1_sha}~1").should == @c_sha
|
761
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
762
|
+
treeish(local_repo, "#{@d_sha}~1").should == @b_sha
|
763
|
+
treeish(origin_repo, "#{@e_sha}~1").should == @b1_sha
|
764
|
+
end
|
765
|
+
|
766
|
+
|
767
|
+
# - A - C - B1 - E - D1
|
768
|
+
# / /
|
769
|
+
# i l,r
|
770
|
+
it 'should work if no conflict' do
|
771
|
+
Given do
|
772
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
773
|
+
rcreate_commit :origin, 'master', :c
|
774
|
+
rfetch local_repo, 'origin'
|
775
|
+
local_repo.create_branch('fb', 'origin/fb')
|
776
|
+
@local.write_sync_control_file('fb')
|
777
|
+
rcreate_commit :local, 'fb', :d
|
778
|
+
rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'b'
|
779
|
+
rcreate_commit :origin, 'fb', :e
|
780
|
+
end
|
781
|
+
|
782
|
+
when_sync_is_run
|
783
|
+
|
784
|
+
Then do
|
785
|
+
local_and_remote_are_same
|
786
|
+
treeish(origin_repo, "#{l_sha}~1").should == @e_sha
|
787
|
+
end
|
788
|
+
end
|
789
|
+
|
790
|
+
|
791
|
+
# i r l
|
792
|
+
# / \ \
|
793
|
+
# - A - C - B1 - E - XX
|
794
|
+
# \
|
795
|
+
# B - D
|
796
|
+
# \
|
797
|
+
# ??
|
798
|
+
it 'should raise an error if there is a conflict' do
|
799
|
+
Given do
|
800
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
801
|
+
rcreate_commit :origin, 'master', :c
|
802
|
+
rfetch local_repo, 'origin'
|
803
|
+
local_repo.create_branch('fb', 'origin/fb')
|
804
|
+
@local.write_sync_control_file('fb')
|
805
|
+
rcreate_commit :local, 'fb', :d, :file => 'a'
|
806
|
+
rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'b'
|
807
|
+
rcreate_commit :origin, 'fb', :e, :file => 'a'
|
808
|
+
end
|
809
|
+
|
810
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
811
|
+
end
|
812
|
+
|
813
|
+
end
|
814
|
+
|
815
|
+
|
816
|
+
# r
|
817
|
+
# \
|
818
|
+
# B1 - E
|
819
|
+
# /
|
820
|
+
# - A - C - F
|
821
|
+
# \ \
|
822
|
+
# B - D i
|
823
|
+
# \
|
824
|
+
# l
|
825
|
+
#
|
826
|
+
# Steps to get to this state:
|
827
|
+
# 1. Changes have been applied to the integration branch
|
828
|
+
# 2. Work has happened locally based on an older version of integration
|
829
|
+
# 3. Work has happened remotely based on rebasing against integration
|
830
|
+
# 4. More work happened on integration
|
831
|
+
#
|
832
|
+
describe 'if local and remote both have work done on them, remote has been rebased with integration, and more work has been done on integration' do
|
833
|
+
|
834
|
+
def verify_start_state
|
835
|
+
l_sha.should == @d_sha
|
836
|
+
r_sha.should == @e_sha
|
837
|
+
i_sha.should == @f_sha
|
838
|
+
treeish(local_repo, "#{@b_sha}~1").should == @a_sha
|
839
|
+
treeish(origin_repo, "#{@b1_sha}~1").should == @c_sha
|
840
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
841
|
+
treeish(local_repo, "#{@d_sha}~1").should == @b_sha
|
842
|
+
treeish(origin_repo, "#{@e_sha}~1").should == @b1_sha
|
843
|
+
treeish(origin_repo, "#{@f_sha}~1").should == @c_sha
|
844
|
+
end
|
845
|
+
|
846
|
+
|
847
|
+
# - A - C - F - B2 - E1 - D1
|
848
|
+
# / /
|
849
|
+
# i l,r
|
850
|
+
it 'should work if no conflict' do
|
851
|
+
Given do
|
852
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
853
|
+
rcreate_commit :origin, 'master', :c
|
854
|
+
rfetch local_repo, 'origin'
|
855
|
+
local_repo.create_branch('fb', 'origin/fb')
|
856
|
+
@local.write_sync_control_file('fb')
|
857
|
+
rcreate_commit :local, 'fb', :d
|
858
|
+
rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'b'
|
859
|
+
rcreate_commit :origin, 'fb', :e
|
860
|
+
rcreate_commit :origin, 'master', :f
|
861
|
+
end
|
862
|
+
|
863
|
+
when_sync_is_run
|
864
|
+
|
865
|
+
Then do
|
866
|
+
local_and_remote_are_same
|
867
|
+
treeish(local_repo, "#{l_sha}~3").should == @f_sha
|
868
|
+
end
|
869
|
+
end
|
870
|
+
|
871
|
+
|
872
|
+
# r
|
873
|
+
# \
|
874
|
+
# B1 - E
|
875
|
+
# /
|
876
|
+
# - A - C - F - XX
|
877
|
+
# \ \ \
|
878
|
+
# B - D i l
|
879
|
+
# \
|
880
|
+
# ??
|
881
|
+
it 'should raise an error if conflict applying remote' do
|
882
|
+
Given do
|
883
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
884
|
+
rcreate_commit :origin, 'master', :c
|
885
|
+
rfetch local_repo, 'origin'
|
886
|
+
local_repo.create_branch('fb', 'origin/fb')
|
887
|
+
@local.write_sync_control_file('fb')
|
888
|
+
rcreate_commit :local, 'fb', :d
|
889
|
+
rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'a'
|
890
|
+
rcreate_commit :origin, 'fb', :e
|
891
|
+
rcreate_commit :origin, 'master', :f, :file => 'a'
|
892
|
+
end
|
893
|
+
|
894
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
895
|
+
end
|
896
|
+
|
897
|
+
|
898
|
+
# r
|
899
|
+
# \
|
900
|
+
# B1 - E
|
901
|
+
# /
|
902
|
+
# - A - C - F - B2 - E1 - XX
|
903
|
+
# \ \ /
|
904
|
+
# B - D i l
|
905
|
+
# \
|
906
|
+
# ??
|
907
|
+
it 'should raise an error if conflict applying local' do
|
908
|
+
Given do
|
909
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
910
|
+
rcreate_commit :origin, 'master', :c
|
911
|
+
rfetch local_repo, 'origin'
|
912
|
+
local_repo.create_branch('fb', 'origin/fb')
|
913
|
+
@local.write_sync_control_file('fb')
|
914
|
+
rcreate_commit :local, 'fb', :d, :file => 'a'
|
915
|
+
rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'b'
|
916
|
+
rcreate_commit :origin, 'fb', :e, :file => 'a'
|
917
|
+
rcreate_commit :origin, 'master', :f
|
918
|
+
end
|
919
|
+
|
920
|
+
expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
|
921
|
+
end
|
922
|
+
|
923
|
+
end
|
924
|
+
|
925
|
+
|
926
|
+
describe 'with branch name' do
|
927
|
+
|
928
|
+
def create_process(gitlib, opts = {})
|
929
|
+
GitProc::Sync.new(gitlib, opts.merge({:branch_name => 'fb', :rebase => true, :force => false}))
|
930
|
+
end
|
931
|
+
|
932
|
+
|
933
|
+
# i
|
934
|
+
# /
|
935
|
+
# - A - C
|
936
|
+
# \
|
937
|
+
# B
|
938
|
+
# \
|
939
|
+
# r
|
940
|
+
#
|
941
|
+
# Steps to get to this state:
|
942
|
+
# 1. There is a remote feature branch ("fb")
|
943
|
+
# 2. The local repo does not have a feature branch by the same name
|
944
|
+
# 3. The integration branch has moved on since the remote branch was last synced
|
945
|
+
describe 'no local branch by the same name' do
|
946
|
+
|
947
|
+
def verify_start_state
|
948
|
+
Rugged::Branch.lookup(local_repo, 'fb').should be_nil
|
949
|
+
r_sha.should == @b_sha
|
950
|
+
i_sha.should == @c_sha
|
951
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
952
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
953
|
+
end
|
954
|
+
|
955
|
+
|
956
|
+
# i l,r
|
957
|
+
# / /
|
958
|
+
# - A - C - B1
|
959
|
+
#
|
960
|
+
it 'creates a local branch and rebases with integration' do
|
961
|
+
Given do
|
962
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
963
|
+
rfetch local_repo, 'origin'
|
964
|
+
rcreate_commit_on_new_branch :local, 'random', 'master', :z, :parents => []
|
965
|
+
rcreate_commit :origin, 'master', :c
|
966
|
+
end
|
967
|
+
|
968
|
+
when_sync_is_run(false)
|
969
|
+
|
970
|
+
Then do
|
971
|
+
local_and_remote_are_same
|
972
|
+
@local.config['branch.fb.remote'].should == 'origin'
|
973
|
+
@local.config['branch.fb.merge'].should == 'refs/heads/master'
|
974
|
+
parent(l_sha).should == @c_sha
|
975
|
+
end
|
976
|
+
end
|
977
|
+
|
978
|
+
end
|
979
|
+
|
980
|
+
|
981
|
+
# i
|
982
|
+
# /
|
983
|
+
# - A - C
|
984
|
+
# \
|
985
|
+
# B - l
|
986
|
+
# \
|
987
|
+
# D - r
|
988
|
+
#
|
989
|
+
# Steps to get to this state:
|
990
|
+
# 1. There is a remote feature branch ("fb")
|
991
|
+
# 2. The local repo has a feature branch by the same name that is fully within the remote's history
|
992
|
+
# 3. The integration branch has moved on since the feature branches were last synced
|
993
|
+
describe 'has local branch by same name subsumed by remote' do
|
994
|
+
|
995
|
+
def verify_start_state
|
996
|
+
Rugged::Branch.lookup(local_repo, 'fb').should_not be_nil
|
997
|
+
l_sha.should == @b_sha
|
998
|
+
r_sha.should == @d_sha
|
999
|
+
i_sha.should == @c_sha
|
1000
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
1001
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
1002
|
+
treeish(origin_repo, "#{@d_sha}~1").should == @b_sha
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
|
1006
|
+
# i l,r
|
1007
|
+
# / /
|
1008
|
+
# - A - C - B1
|
1009
|
+
#
|
1010
|
+
it 'change to the remote and rebases with integration if it is subsumed by the remote' do
|
1011
|
+
Given do
|
1012
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
1013
|
+
rfetch local_repo, 'origin'
|
1014
|
+
local_repo.create_branch('fb', 'origin/fb')
|
1015
|
+
rcreate_commit :origin, 'fb', :d
|
1016
|
+
rcreate_commit :origin, 'master', :c
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
when_sync_is_run(false)
|
1020
|
+
|
1021
|
+
Then do
|
1022
|
+
local_and_remote_are_same
|
1023
|
+
@local.config['branch.fb.remote'].should == 'origin'
|
1024
|
+
@local.config['branch.fb.merge'].should == 'refs/heads/master'
|
1025
|
+
parent(l_sha).should == @c_sha
|
1026
|
+
end
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
|
1032
|
+
# i
|
1033
|
+
# /
|
1034
|
+
# - A - C
|
1035
|
+
# \
|
1036
|
+
# B
|
1037
|
+
# \
|
1038
|
+
# r
|
1039
|
+
#
|
1040
|
+
# Steps to get to this state:
|
1041
|
+
# 1. There is a remote feature branch ("fb")
|
1042
|
+
# 2. The local repo has a feature branch by the same name not fully in the remote's history
|
1043
|
+
# 3. The integration branch has moved on since the remote branch was last synced
|
1044
|
+
describe 'has local branch by same name not subsumed by remote' do
|
1045
|
+
|
1046
|
+
def verify_start_state
|
1047
|
+
Rugged::Branch.lookup(local_repo, 'fb').should_not be_nil
|
1048
|
+
r_sha.should == @b_sha
|
1049
|
+
i_sha.should == @c_sha
|
1050
|
+
treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
|
1051
|
+
treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
|
1055
|
+
# i l,r
|
1056
|
+
# / /
|
1057
|
+
# - A - C - B1
|
1058
|
+
#
|
1059
|
+
it 'should fail if it is not subsumed by the remote' do
|
1060
|
+
Given do
|
1061
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
1062
|
+
rcreate_commit_on_new_branch :local, 'fb', 'master', :z, :parents => []
|
1063
|
+
rcreate_commit :origin, 'master', :c
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
expect { when_sync_is_run(false) }.to raise_error(GitProcessError, /is not fully subsumed by origin\/fb/)
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
|
1072
|
+
describe 'unknown branch name' do
|
1073
|
+
|
1074
|
+
def create_process(gitlib, opts = {})
|
1075
|
+
GitProc::Sync.new(gitlib, opts.merge({:branch_name => 'unknown', :rebase => true, :force => false}))
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
|
1079
|
+
def verify_start_state
|
1080
|
+
Rugged::Branch.lookup(origin_repo, 'fb').should_not be_nil
|
1081
|
+
Rugged::Branch.lookup(local_repo, 'unknown').should be_nil
|
1082
|
+
Rugged::Branch.lookup(origin_repo, 'unknown').should be_nil
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
|
1086
|
+
it 'should fail if it is not subsumed by the remote' do
|
1087
|
+
Given do
|
1088
|
+
rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
expect { when_sync_is_run(false) }.to raise_error(GitProcessError, /There is not a remote branch for 'unknown'/)
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
|
1097
|
+
describe 'no remote' do
|
1098
|
+
|
1099
|
+
def create_process(gitlib, opts = {})
|
1100
|
+
GitProc::Sync.new(gitlib, opts.merge({:branch_name => 'no_remote', :rebase => true, :force => false}))
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
|
1104
|
+
def verify_start_state
|
1105
|
+
Rugged::Branch.lookup(local_repo, 'no_remote').should be_nil
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
|
1109
|
+
it 'should fail if it is not subsumed by the remote' do
|
1110
|
+
Given do
|
1111
|
+
@local.command(:remote, ['remove', 'origin'])
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
expect { when_sync_is_run(false) }.to raise_error(GitProcessError, /Specifying 'no_remote' does not make sense without a remote/)
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
|
1124
|
+
describe 'when forcing local-only' do
|
1125
|
+
|
1126
|
+
def create_process(dir, opts)
|
1127
|
+
GitProc::Sync.new(dir, opts.merge({:rebase => true, :force => false, :local => true}))
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
|
1131
|
+
it 'should not try to push' do
|
1132
|
+
change_file_and_commit('a', '')
|
1133
|
+
|
1134
|
+
gitlib.branch('fb', :base_branch => 'master')
|
1135
|
+
|
1136
|
+
clone_repo('fb') do |gl|
|
1137
|
+
gitlib.checkout('fb')
|
1138
|
+
change_file_and_commit('a', 'hello', gitlib)
|
1139
|
+
|
1140
|
+
sp = GitProc::Sync.new(gl, :rebase => true, :force => false, :local => true, :log_level => log_level)
|
1141
|
+
gl.should_receive(:fetch).at_least(1) # want to get remote changes
|
1142
|
+
gl.should_not_receive(:push) # ...but not push any
|
1143
|
+
|
1144
|
+
sp.runner
|
1145
|
+
end
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
end
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
|
1152
|
+
describe 'when there is no remote' do
|
1153
|
+
|
1154
|
+
def create_process(base, opts)
|
1155
|
+
GitProc::Sync.new(base, opts.merge({:rebase => true, :force => false, :local => false}))
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
|
1159
|
+
it 'should not try to fetch or push' do
|
1160
|
+
change_file_and_commit('a', '')
|
1161
|
+
|
1162
|
+
gitlib.branch('fb', :base_branch => 'master')
|
1163
|
+
|
1164
|
+
sp = GitProc::Sync.new(gitlib, :rebase => true, :force => false, :local => true, :log_level => log_level)
|
1165
|
+
gitlib.should_not_receive(:fetch)
|
1166
|
+
gitlib.should_not_receive(:push)
|
1167
|
+
|
1168
|
+
sp.runner
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
|
1174
|
+
describe 'when default rebase flag is used' do
|
1175
|
+
|
1176
|
+
def create_process(base = gitlib, opts = {})
|
1177
|
+
GitProc::Sync.new(base, opts.merge({:rebase => false, :force => false, :local => false}))
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
|
1181
|
+
it 'should try to rebase by flag' do
|
1182
|
+
change_file_and_commit('a', '', gitlib)
|
1183
|
+
|
1184
|
+
gitlib.branch('fb', :base_branch => 'master')
|
1185
|
+
|
1186
|
+
sp = GitProc::Sync.new(gitlib, :rebase => true, :force => false, :local => true, :log_level => log_level)
|
1187
|
+
gitlib.should_receive(:rebase)
|
1188
|
+
gitlib.should_not_receive(:merge)
|
1189
|
+
|
1190
|
+
sp.runner
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
|
1194
|
+
it 'should try to rebase by config' do
|
1195
|
+
change_file_and_commit('a', '', gitlib)
|
1196
|
+
|
1197
|
+
gitlib.branch('fb', :base_branch => 'master')
|
1198
|
+
gitlib.config.default_rebase_sync = true
|
1199
|
+
|
1200
|
+
sp = GitProc::Sync.new(gitlib, :force => false, :local => true, :log_level => log_level)
|
1201
|
+
gitlib.should_receive(:rebase)
|
1202
|
+
gitlib.should_not_receive(:merge)
|
1203
|
+
|
1204
|
+
sp.runner
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
|
1208
|
+
it 'should not try to rebase by false config' do
|
1209
|
+
change_file_and_commit('a', '', gitlib)
|
1210
|
+
|
1211
|
+
gitlib.branch('fb', :base_branch => 'master')
|
1212
|
+
gitlib.config.default_rebase_sync = false
|
1213
|
+
|
1214
|
+
sp = GitProc::Sync.new(gitlib, :rebase => false, :force => false, :local => true, :log_level => log_level)
|
1215
|
+
gitlib.should_not_receive(:rebase)
|
1216
|
+
gitlib.should_receive(:merge)
|
1217
|
+
|
1218
|
+
sp.runner
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
|
1222
|
+
it 'should try to rebase by true flag config' do
|
1223
|
+
change_file_and_commit('a', '', gitlib)
|
1224
|
+
|
1225
|
+
gitlib.branch('fb', :base_branch => 'master')
|
1226
|
+
gitlib.config.default_rebase_sync = false
|
1227
|
+
|
1228
|
+
sp = GitProc::Sync.new(gitlib, :rebase => true, :force => false, :local => true, :log_level => log_level)
|
1229
|
+
gitlib.should_receive(:rebase)
|
1230
|
+
gitlib.should_not_receive(:merge)
|
1231
|
+
|
1232
|
+
sp.runner
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
|
1236
|
+
it 'should not try to rebase by false flag config' do
|
1237
|
+
change_file_and_commit('a', '', gitlib)
|
1238
|
+
|
1239
|
+
gitlib.branch('fb', :base_branch => 'master')
|
1240
|
+
gitlib.config.default_rebase_sync = true
|
1241
|
+
|
1242
|
+
sp = GitProc::Sync.new(gitlib, :rebase => false, :force => false, :local => true, :log_level => log_level)
|
1243
|
+
gitlib.should_not_receive(:rebase)
|
1244
|
+
gitlib.should_receive(:merge)
|
1245
|
+
|
1246
|
+
sp.runner
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
|
1252
|
+
it "should work with a different remote server name than 'origin'" do
|
1253
|
+
change_file_and_commit('a', '')
|
1254
|
+
|
1255
|
+
gitlib.branch('fb', :base_branch => 'master')
|
1256
|
+
|
1257
|
+
clone_repo('fb', 'a_remote') do |gl|
|
1258
|
+
change_file_and_commit('a', 'hello', gl)
|
1259
|
+
gl.branches.include?('a_remote/fb').should be_true
|
1260
|
+
|
1261
|
+
GitProc::Sync.new(gl, :rebase => false, :force => false, :log_level => log_level).runner
|
1262
|
+
|
1263
|
+
gl.branches.include?('a_remote/fb').should be_true
|
1264
|
+
gitlib.branches.include?('fb').should be_true
|
1265
|
+
end
|
1266
|
+
end
|
1267
|
+
|
1268
|
+
|
1269
|
+
it 'should fail when removing current feature while on _parking_' do
|
1270
|
+
gitlib.checkout('_parking_', :new_branch => 'master')
|
1271
|
+
change_file_and_commit('a', '')
|
1272
|
+
|
1273
|
+
expect { gitprocess.verify_preconditions }.to raise_error ParkedChangesError
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
|
1277
|
+
###########################################################################
|
1278
|
+
#
|
1279
|
+
# HELPER METHODS
|
1280
|
+
#
|
1281
|
+
###########################################################################
|
1282
|
+
|
1283
|
+
|
1284
|
+
#noinspection RubyInstanceMethodNamingConvention
|
1285
|
+
def Given
|
1286
|
+
if block_given?
|
1287
|
+
yield
|
1288
|
+
verify_start_state
|
1289
|
+
else
|
1290
|
+
raise ArgumentError, 'No block given'
|
1291
|
+
end
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
|
1295
|
+
def when_sync_is_run(do_checkout = true)
|
1296
|
+
@local.checkout('fb') if do_checkout
|
1297
|
+
create_process(@local).runner
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
|
1301
|
+
#noinspection RubyInstanceMethodNamingConvention
|
1302
|
+
def Then
|
1303
|
+
if block_given?
|
1304
|
+
yield
|
1305
|
+
else
|
1306
|
+
raise ArgumentError, 'No block given'
|
1307
|
+
end
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
|
1311
|
+
def origin(branchname = nil, opts={})
|
1312
|
+
unless @origin
|
1313
|
+
@origin = gitlib
|
1314
|
+
@origin.config['receive.denyCurrentBranch'] = 'ignore'
|
1315
|
+
end
|
1316
|
+
@current_lib = @origin
|
1317
|
+
@origin.checkout(branchname, opts) if branchname
|
1318
|
+
@origin
|
1319
|
+
end
|
1320
|
+
|
1321
|
+
|
1322
|
+
def local(branchname = nil, opts={})
|
1323
|
+
if @local.nil?
|
1324
|
+
remote_name = opts[:remote_name] || 'origin'
|
1325
|
+
@local ||= clone_repo('master', remote_name)
|
1326
|
+
end
|
1327
|
+
@current_lib = @local
|
1328
|
+
@local.fetch
|
1329
|
+
@local.checkout(branchname, opts) if branchname
|
1330
|
+
@local
|
1331
|
+
end
|
1332
|
+
|
1333
|
+
|
1334
|
+
def parent(sha, lib = @local)
|
1335
|
+
lib.fetch
|
1336
|
+
@local.sha("#{sha}~1")
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
|
1340
|
+
def create_commit(commit_name, opts={})
|
1341
|
+
lib = opts[:lib] || @current_lib
|
1342
|
+
raise ArgumentError, 'missing lib' unless lib
|
1343
|
+
|
1344
|
+
filename = opts[:file] || commit_name.to_s
|
1345
|
+
change_file_and_commit(filename, "#{commit_name} contents", lib)
|
1346
|
+
instance_variable_set("@#{commit_name}_sha", lib.sha('HEAD'))
|
1347
|
+
end
|
1348
|
+
|
1349
|
+
|
1350
|
+
def check_file_content(commit_name, opts={})
|
1351
|
+
lib = opts[:lib] || @local
|
1352
|
+
|
1353
|
+
filename = opts[:file] || commit_name.to_s
|
1354
|
+
File.open(File.join(lib.workdir, filename)).read.should == "#{commit_name} contents\n"
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
|
1358
|
+
#noinspection RubyInstanceMethodNamingConvention
|
1359
|
+
def create_feature_branch_on_origin
|
1360
|
+
@origin.checkout('fb', :new_branch => 'master')
|
1361
|
+
end
|
1362
|
+
|
1363
|
+
|
1364
|
+
def local_repo
|
1365
|
+
@local_repo ||= Rugged::Repository.new(@local.workdir)
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
|
1369
|
+
def origin_repo
|
1370
|
+
@origin_repo ||= Rugged::Repository.new(@origin.workdir)
|
1371
|
+
end
|
1372
|
+
|
1373
|
+
|
1374
|
+
def l_sha
|
1375
|
+
branch_tip(local_repo, 'fb')
|
1376
|
+
end
|
1377
|
+
|
1378
|
+
|
1379
|
+
def i_sha
|
1380
|
+
branch_tip(origin_repo, 'master')
|
1381
|
+
end
|
1382
|
+
|
1383
|
+
|
1384
|
+
def r_sha
|
1385
|
+
branch_tip(origin_repo, 'fb')
|
1386
|
+
end
|
1387
|
+
|
1388
|
+
|
1389
|
+
def local_and_remote_are_same
|
1390
|
+
l_sha.should == r_sha
|
1391
|
+
end
|
1392
|
+
|
1393
|
+
|
1394
|
+
def branch_tip(repo, branch_name)
|
1395
|
+
Rugged::Branch.lookup(repo, branch_name).tip.oid
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
|
1399
|
+
def rchange_file_and_commit(repo_name, branch, filename, contents, opts = {})
|
1400
|
+
repo = self.method("#{repo_name.to_s}_repo").call
|
1401
|
+
|
1402
|
+
content_oid = repo.write(contents, :blob)
|
1403
|
+
logger.debug { "\nwrote content '#{contents}' to #{content_oid}" }
|
1404
|
+
|
1405
|
+
if branch.nil?
|
1406
|
+
tree = Rugged::Tree::Builder.new
|
1407
|
+
tree.insert(:name => filename, :oid => content_oid, :filemode => 0100644)
|
1408
|
+
tree_oid = tree.write(repo)
|
1409
|
+
parents = opts[:parents] || []
|
1410
|
+
branch_name = 'HEAD'
|
1411
|
+
else
|
1412
|
+
tree = Rugged::Tree::Builder.new(branch.tip.tree)
|
1413
|
+
tree.insert(:name => filename, :oid => content_oid, :filemode => 0100644)
|
1414
|
+
tree_oid = tree.write(repo)
|
1415
|
+
parents = opts[:parents] || [branch.tip.oid]
|
1416
|
+
branch_name = branch.canonical_name
|
1417
|
+
end
|
1418
|
+
|
1419
|
+
tree = repo.lookup(tree_oid)
|
1420
|
+
logger.debug "tree:"
|
1421
|
+
tree.each { |entry| logger.debug " #{entry.inspect}" }
|
1422
|
+
|
1423
|
+
person = {:name => 'test user', :email => 'test.user@test.com', :time => Time.now, :time_offset => 3600}
|
1424
|
+
oid = Rugged::Commit.create(repo,
|
1425
|
+
:message => "#{filename} - #{contents}",
|
1426
|
+
:committer => person,
|
1427
|
+
:author => person,
|
1428
|
+
:parents => parents,
|
1429
|
+
:update_ref => branch_name,
|
1430
|
+
:tree => tree_oid)
|
1431
|
+
|
1432
|
+
new_branch = Rugged::Branch.lookup(repo, branch.nil? ? 'HEAD' : branch.name)
|
1433
|
+
new_tip = new_branch.nil? ? 'BUG' : new_branch.tip.oid
|
1434
|
+
logger.debug { "wrote commit #{oid} on #{repo_name} - #{branch_name} with #{parents} as the parent, making new branch tip #{new_tip}" }
|
1435
|
+
oid
|
1436
|
+
end
|
1437
|
+
|
1438
|
+
|
1439
|
+
def rcreate_commit(repo_name, branch_name, commit_name, opts={})
|
1440
|
+
repo = self.method("#{repo_name.to_s}_repo").call
|
1441
|
+
branch = Rugged::Branch.lookup(repo, branch_name)
|
1442
|
+
_create_commit(repo_name, branch, commit_name, opts)
|
1443
|
+
end
|
1444
|
+
|
1445
|
+
|
1446
|
+
def _create_commit(repo_name, branch, commit_name, opts)
|
1447
|
+
filename = opts[:file] || commit_name.to_s
|
1448
|
+
oid = rchange_file_and_commit(repo_name, branch, filename, "#{commit_name} contents\n", opts)
|
1449
|
+
instance_variable_set("@#{commit_name}_sha", oid)
|
1450
|
+
oid
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
|
1454
|
+
def rcreate_commit_on_new_branch(repo_name, branch_name, base_branch_name, commit_name, opts={})
|
1455
|
+
repo = self.method("#{repo_name.to_s}_repo").call
|
1456
|
+
branch = repo.create_branch(branch_name, base_branch_name)
|
1457
|
+
_create_commit(repo_name, branch, commit_name, opts)
|
1458
|
+
end
|
1459
|
+
|
1460
|
+
|
1461
|
+
def rfetch(repo, remote_name)
|
1462
|
+
remote = Rugged::Remote.lookup(repo, remote_name)
|
1463
|
+
remote.connect(:fetch) do |r|
|
1464
|
+
r.download()
|
1465
|
+
r.update_tips!
|
1466
|
+
end
|
1467
|
+
end
|
1468
|
+
|
1469
|
+
|
1470
|
+
def treeish(repo, treeish)
|
1471
|
+
Rugged::Object.rev_parse(repo, treeish).oid
|
1472
|
+
end
|
1473
|
+
|
1474
|
+
end
|