git-improved 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1953 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+
5
+ require_relative "shared"
6
+
7
+
8
+ Oktest.scope do
9
+
10
+
11
+ topic GitImproved::GitAction do
12
+
13
+ before_all do
14
+ @pwd = Dir.pwd()
15
+ @dir = "_repo#{rand().to_s[2..6]}"
16
+ Dir.mkdir @dir
17
+ Dir.chdir @dir
18
+ system "git init -q -b main" , exception: true
19
+ system "git config user.name user1" , exception: true
20
+ system "git config user.email user1@gmail.com" , exception: true
21
+ system "git commit --allow-empty -q -m 'Initial commit (empty)'", exception: true
22
+ $initial_commit_id = `git rev-parse HEAD`.strip()
23
+ end
24
+
25
+ after_all do
26
+ Dir.chdir @pwd
27
+ Benry::UnixCommand.echoback_off do
28
+ Benry::UnixCommand.rm :rf, @dir
29
+ end
30
+ end
31
+
32
+ before do
33
+ system! "git checkout -q main"
34
+ end
35
+
36
+
37
+ topic('branch:') {
38
+
39
+ topic 'branch:checkout' do
40
+ spec "create a new local branch from a remote branch" do
41
+ ## TODO
42
+ dryrun_mode do
43
+ _, sout = main "branch:checkout", "remoterepo"
44
+ ok {sout} == <<~"END"
45
+ [gi]$ git checkout -b remoterepo origin/remoterepo
46
+ END
47
+ end
48
+ end
49
+ end
50
+
51
+ topic 'branch:create' do
52
+ spec "create a new branch, not switch to it" do
53
+ br = "br7625"
54
+ _, sout = main "branch:create", br
55
+ ok {sout} == "[gi]$ git branch br7625\n"
56
+ ok {`git branch`} =~ /br7625/
57
+ curr = curr_branch()
58
+ ok {curr} != br
59
+ ok {curr} == "main"
60
+ end
61
+ end
62
+
63
+ topic 'branch:delete' do
64
+ spec "delete a branch" do
65
+ br = "br6993"
66
+ system! "git branch #{br}"
67
+ ok {`git branch`} =~ /#{br}/
68
+ _, sout = main "branch:delete", br
69
+ ok {sout} == "[gi]$ git branch -d br6993\n"
70
+ ok {`git branch`} !~ /#{br}/
71
+ end
72
+ end
73
+
74
+ topic 'branch:fork' do
75
+ spec "create a new branch and switch to it" do
76
+ br = "br2555"
77
+ ok {curr_branch()} == "main"
78
+ _, sout = main "branch:fork", br
79
+ ok {sout} == "[gi]$ git checkout -b br2555\n"
80
+ ok {curr_branch()} == br
81
+ end
82
+ end
83
+
84
+ topic 'branch:join' do
85
+ spec "merge current branch into previous or other branch" do
86
+ br = "br0807"
87
+ system! "git checkout -q -b #{br}"
88
+ ok {curr_branch()} == br
89
+ system! "git commit --allow-empty -q -m 'test'"
90
+ _, sout = main "branch:join", stdin: "\n"
91
+ ok {sout} == <<~"END"
92
+ Merge current branch '\e[1mbr0807\e[0m' into '\e[1mmain\e[0m'. OK? [Y/n]: [gi]$ git checkout main
93
+ [gi]$ git merge --no-ff -
94
+ END
95
+ ok {curr_branch()} == "main"
96
+ end
97
+ end
98
+
99
+ topic 'branch:list' do
100
+ spec "list branches" do
101
+ system! "git branch br1845x"
102
+ system! "git branch br1845y"
103
+ output, sout = main "branch:list"
104
+ ok {sout} == "[gi]$ git branch -a\n"
105
+ ok {output} =~ /^\* main$/
106
+ ok {output} =~ /^ br1845x$/
107
+ ok {output} =~ /^ br1845y$/
108
+ end
109
+ end
110
+
111
+ topic 'branch:merge' do
112
+ spec "merge previous or other branch into current branch" do
113
+ br = "br7231"
114
+ system! "git branch -q #{br}"
115
+ system! "git checkout -q #{br}"
116
+ system! "git commit --allow-empty -q -m 'test commit on #{br}'"
117
+ system! "git checkout -q main"
118
+ _, sout = main "branch:merge", stdin: "\n"
119
+ ok {sout} == <<~"END"
120
+ Merge '\e[1mbr7231\e[0m' branch into '\e[1mmain\e[0m'. OK? [Y/n]: [gi]$ git merge --no-ff br7231
121
+ END
122
+ ok {`git log -1 --oneline`} =~ /\A\h{7} Merge branch '#{br}'$/
123
+ ok {`git log --oneline`} =~ /test commit on #{br}/
124
+ end
125
+ end
126
+
127
+ topic 'branch:rebase' do
128
+ before do
129
+ _reset_all_commits()
130
+ end
131
+ def _prepare(base_branch)
132
+ br = base_branch
133
+ system! "git checkout -q -b #{br}dev"
134
+ system! "git commit --allow-empty -q -m 'on #{br}dev #1'"
135
+ system! "git commit --allow-empty -q -m 'on #{br}dev #2'"
136
+ #
137
+ system! "git checkout -q -b #{br}fix"
138
+ system! "git commit --allow-empty -q -m 'on #{br}fix #3'"
139
+ system! "git commit --allow-empty -q -m 'on #{br}fix #4'"
140
+ #
141
+ system! "git checkout -q #{br}dev"
142
+ system! "git commit --allow-empty -q -m 'on #{br}dev #5'"
143
+ system! "git commit --allow-empty -q -m 'on #{br}dev #6'"
144
+ #
145
+ system! "git checkout -q main"
146
+ system! "git commit --allow-empty -q -m 'on main #7'"
147
+ system! "git commit --allow-empty -q -m 'on main #8'"
148
+ end
149
+ spec "rebase (move) current branch on top of other branch" do
150
+ br = "br7108"
151
+ _prepare(br)
152
+ #
153
+ system! "git checkout -q #{br}dev"
154
+ system! "git checkout -q #{br}fix"
155
+ ok {`git log --oneline`} =~ partial_regexp(<<~"END")
156
+ {==\\h{7}==} on #{br}fix #4
157
+ {==\\h{7}==} on #{br}fix #3
158
+ {==\\h{7}==} on #{br}dev #2
159
+ {==\\h{7}==} on #{br}dev #1
160
+ {==\\h{7}==} Initial commit (empty)
161
+ END
162
+ #
163
+ output, sout = main "branch:rebase", "-"
164
+ ok {sout} == "[gi]$ git rebase #{br}dev\n"
165
+ ok {output}.end_with?("Successfully rebased and updated refs/heads/#{br}fix.\n")
166
+ ok {`git log --oneline`} =~ partial_regexp(<<~"END")
167
+ {==\\h{7}==} on #{br}fix #4
168
+ {==\\h{7}==} on #{br}fix #3
169
+ {==\\h{7}==} on #{br}dev #6
170
+ {==\\h{7}==} on #{br}dev #5
171
+ {==\\h{7}==} on #{br}dev #2
172
+ {==\\h{7}==} on #{br}dev #1
173
+ {==\\h{7}==} Initial commit (empty)
174
+ END
175
+ end
176
+ spec "second arg represents upstream branch." do
177
+ br = "br5419"
178
+ _prepare(br)
179
+ #
180
+ system! "git checkout -q #{br}fix"
181
+ ok {`git log --oneline`} =~ partial_regexp(<<~"END")
182
+ {==\\h{7}==} on #{br}fix #4
183
+ {==\\h{7}==} on #{br}fix #3
184
+ {==\\h{7}==} on #{br}dev #2
185
+ {==\\h{7}==} on #{br}dev #1
186
+ {==\\h{7}==} Initial commit (empty)
187
+ END
188
+ #
189
+ ok {curr_branch()} == "#{br}fix"
190
+ output, sout = main "branch:rebase", "main", "#{br}dev"
191
+ ok {sout} == <<~"END"
192
+ [gi]$ git rebase --onto=main #{br}dev
193
+ END
194
+ ok {output}.end_with?("Successfully rebased and updated refs/heads/#{br}fix.\n")
195
+ ok {`git log --oneline`} =~ partial_regexp(<<~"END")
196
+ {==\\h{7}==} on #{br}fix #4
197
+ {==\\h{7}==} on #{br}fix #3
198
+ {==\\h{7}==} on main #8
199
+ {==\\h{7}==} on main #7
200
+ {==\\h{7}==} Initial commit (empty)
201
+ END
202
+ end
203
+ spec "option '--from' specifies commit-id to start." do
204
+ br = "br3886"
205
+ _prepare(br)
206
+ #
207
+ system! "git checkout -q #{br}dev"
208
+ ok {`git log --oneline`} =~ partial_regexp(<<~"END")
209
+ {==\\h{7}==} on #{br}dev #6
210
+ {==\\h{7}==} on #{br}dev #5
211
+ {==\\h{7}==} on #{br}dev #2
212
+ {==\\h{7}==} on #{br}dev #1
213
+ {==\\h{7}==} Initial commit (empty)
214
+ END
215
+ `git log --oneline` =~ /^(\h+) on #{br}dev #2/
216
+ commit_id = $1
217
+ ok {commit_id} != nil
218
+ #
219
+ output, sout = main "branch:rebase", "-", "--from=#{commit_id}"
220
+ ok {sout} == <<~"END"
221
+ [gi]$ git rebase --onto=main #{commit_id}^
222
+ END
223
+ ok {output}.end_with?("Successfully rebased and updated refs/heads/br3886dev.\n")
224
+ ok {`git log --oneline`} =~ partial_regexp(<<~"END")
225
+ {==\\h{7}==} on #{br}dev #6
226
+ {==\\h{7}==} on #{br}dev #5
227
+ {==\\h{7}==} on #{br}dev #2
228
+ {==\\h{7}==} on main #8
229
+ {==\\h{7}==} on main #7
230
+ {==\\h{7}==} Initial commit (empty)
231
+ END
232
+ end
233
+ end
234
+
235
+ topic 'branch:rename' do
236
+ spec "rename the current branch to other name" do
237
+ br = "br4571"
238
+ system! "git checkout -q -b #{br}"
239
+ ok {curr_branch()} == br
240
+ output, sout = main "branch:rename", "#{br}fix"
241
+ ok {sout} == "[gi]$ git branch -m br4571 br4571fix\n"
242
+ ok {output} == ""
243
+ ok {curr_branch()} == "#{br}fix"
244
+ end
245
+ end
246
+
247
+ topic 'branch:reset' do
248
+ spec "change commit-id of current HEAD" do
249
+ system "git commit --allow-empty -q -m 'test #1'"
250
+ commit_id1 = `git rev-parse HEAD`[0..6]
251
+ system "git commit --allow-empty -q -m 'test #2'"
252
+ system "git commit --allow-empty -q -m 'test #3'"
253
+ commit_id3 = `git rev-parse HEAD`[0..6]
254
+ ok {commit_id1} != commit_id3
255
+ #
256
+ ok {`git rev-parse HEAD`[0..6]} != commit_id1
257
+ output, sout = main "branch:reset", commit_id1
258
+ ok {sout} == "[gi]$ git reset #{commit_id1}\n"
259
+ ok {output} == ""
260
+ ok {`git rev-parse HEAD`[0..6]} == commit_id1
261
+ #
262
+ output, sout = main "branch:reset", commit_id3
263
+ ok {sout} == "[gi]$ git reset #{commit_id3}\n"
264
+ ok {output} == ""
265
+ ok {`git rev-parse HEAD`[0..6]} == commit_id3
266
+ end
267
+ end
268
+
269
+ topic 'branch:switch' do
270
+ spec "switch to previous or other branch" do
271
+ br = "br3413"
272
+ system! "git branch -q #{br}"
273
+ ok {curr_branch()} == "main"
274
+ #
275
+ output, sout = main "branch:switch", br
276
+ ok {sout} == "[gi]$ git checkout #{br}\n"
277
+ ok {output} == "Switched to branch '#{br}'\n"
278
+ ok {curr_branch()} == br
279
+ #
280
+ output, sout = main "branch:switch"
281
+ ok {sout} == "[gi]$ git checkout -\n"
282
+ ok {output} == "Switched to branch 'main'\n"
283
+ ok {curr_branch()} == "main"
284
+ end
285
+ end
286
+
287
+ topic 'branch:update' do
288
+ def _prepare()
289
+ br = "br6209"
290
+ file = "file6209.txt"
291
+ #system! "git remote add origin git@github.com:u1/r1.git"
292
+ #system! "git config advice.setUpstreamFailure false"
293
+ #system! "git branch -u origin main"
294
+ #at_end { system! "git remote remove origin" }
295
+ system! "git config branch.main.remote origin"
296
+ at_end { system! "git config --unset branch.main.remote" }
297
+ system! "git checkout -q main"
298
+ system! "git checkout -q -b #{br}"
299
+ dummy_file(file, "A\n")
300
+ system! "git add #{file}"
301
+ system! "git commit -q -m 'add #{file} #1'"
302
+ system! "git checkout -q -b origin/main"
303
+ system! "git commit --allow-empty -q -m 'test #2'"
304
+ system! "git checkout -q main"
305
+ system! "git commit --allow-empty -q -m 'test #3'"
306
+ system! "git checkout -q #{br}"
307
+ writefile(file, "A\nB\n")
308
+ end
309
+ spec "git pull && git stash && git rebase && git stash pop" do
310
+ ## TODO
311
+ _prepare()
312
+ dryrun_mode do
313
+ output, sout = main "branch:update", "-b"
314
+ ok {sout} == <<~"END"
315
+ [INFO] previous: main, remote: origin
316
+ [gi]$ git fetch
317
+ [gi]$ git stash push -q
318
+ [gi]$ git checkout -q main
319
+ [gi]$ git pull
320
+ [gi]$ git checkout -q -
321
+ [gi]$ git rebase main
322
+ [gi]$ git stash pop -q
323
+ END
324
+ ok {output} == ""
325
+ end
326
+ end
327
+ end
328
+
329
+ topic 'branch:upstream' do
330
+ spec "print upstream repo name of current branch" do
331
+ br = "br2950"
332
+ system! "git checkout -q -b #{br}"
333
+ output, sout = main "branch:upstream"
334
+ ok {sout} == <<~'END'
335
+ [gi]$ git config --get-regexp '^branch\.br2950\.remote' | awk '{print $2}'
336
+ END
337
+ ok {output} == ""
338
+ #system! "git remote add origin git@github.com:user1/repo1.git"
339
+ system! "git config branch.#{br}.remote origin"
340
+ output, sout = main "branch:upstream"
341
+ ok {sout} == <<~'END'
342
+ [gi]$ git config --get-regexp '^branch\.br2950\.remote' | awk '{print $2}'
343
+ origin
344
+ END
345
+ ok {output} == ""
346
+ end
347
+ end
348
+
349
+ topic 'branch:current' do
350
+ spec "show current branch name" do
351
+ output, sout = main "branch:current"
352
+ ok {sout} == "[gi]$ git rev-parse --abbrev-ref HEAD\n"
353
+ ok {output} == "main\n"
354
+ end
355
+ end
356
+
357
+ topic 'branch:parent' do
358
+ spec "show parent branch name (EXPERIMENTAL)" do
359
+ br = "br6489"
360
+ system! "git commit --allow-empty -q -m 'for #{br} #1'"
361
+ system! "git checkout -q -b #{br}"
362
+ system! "git commit --allow-empty -q -m 'for #{br} #2'"
363
+ ok {curr_branch()} == br
364
+ _, sout = main "branch:parent"
365
+ ok {sout} == <<~'END'
366
+ [gi]$ git show-branch -a | sed 's/].*//' | grep '\*' | grep -v "\\[$(git branch --show-current)\$" | head -n1 | sed 's/^.*\[//'
367
+ main
368
+ END
369
+ #
370
+ system! "git checkout -q -b #{br}x"
371
+ ok {curr_branch()} == "#{br}x"
372
+ _, sout = main "branch:parent"
373
+ ok {sout} == <<~'END'
374
+ [gi]$ git show-branch -a | sed 's/].*//' | grep '\*' | grep -v "\\[$(git branch --show-current)\$" | head -n1 | sed 's/^.*\[//'
375
+ br6489
376
+ END
377
+ end
378
+ end
379
+
380
+ topic 'branch:previous' do
381
+ spec "show previous branch name" do
382
+ br = "br0184"
383
+ #
384
+ system! "git checkout -q -b #{br}"
385
+ output, sout = main "branch:previous"
386
+ ok {sout} == "[gi]$ git rev-parse --abbrev-ref \"@{-1}\"\n"
387
+ ok {output} == "main\n"
388
+ #
389
+ system! "git checkout -q -b #{br}xx"
390
+ output, sout = main "branch:previous"
391
+ ok {sout} == "[gi]$ git rev-parse --abbrev-ref \"@{-1}\"\n"
392
+ ok {output} == "#{br}\n"
393
+ end
394
+ end
395
+
396
+ topic 'branch:echo' do
397
+ #spec "print CURR/PREV/PARENT branch name"
398
+ spec "print current branch name if argument is 'CURR'." do
399
+ br = "br1129"
400
+ system! "git checkout -q -b #{br}"
401
+ output, sout = main "branch:echo", "CURR"
402
+ ok {sout} == "[gi]$ git rev-parse --abbrev-ref HEAD\n"
403
+ ok {output} == "#{br}\n"
404
+ system! "git checkout -q main"
405
+ output, sout = main "branch:echo", "CURR"
406
+ ok {sout} == "[gi]$ git rev-parse --abbrev-ref HEAD\n"
407
+ ok {output} == "main\n"
408
+ end
409
+ spec "print previous branch name if argument is 'PREV'." do
410
+ br = "br0183"
411
+ system! "git checkout -q -b #{br}"
412
+ output, sout = main "branch:echo", "PREV"
413
+ ok {sout} == "[gi]$ git rev-parse --abbrev-ref \"@{-1}\"\n"
414
+ ok {output} == "main\n"
415
+ system! "git checkout -q -b #{br}xx"
416
+ output, sout = main "branch:echo", "PREV"
417
+ ok {sout} == "[gi]$ git rev-parse --abbrev-ref \"@{-1}\"\n"
418
+ ok {output} == "#{br}\n"
419
+ end
420
+ spec "print parent branch name if argument is 'PARENT'." do
421
+ br = "br6488"
422
+ delete_all_branches_except_main()
423
+ system! "git checkout -q main"
424
+ system! "git commit --allow-empty -q -m 'for #{br} #1'"
425
+ system! "git checkout -q -b #{br}"
426
+ system! "git commit --allow-empty -q -m 'for #{br} #2'"
427
+ ok {curr_branch()} == br
428
+ output, sout = main "branch:echo", "PARENT"
429
+ ok {sout} == <<~'END'
430
+ [gi]$ git show-branch -a | sed 's/].*//' | grep '\*' | grep -v "\\[$(git branch --show-current)\$" | head -n1 | sed 's/^.*\[//'
431
+ main
432
+ END
433
+ ok {output} == ""
434
+ #
435
+ system! "git checkout -q -b #{br}x"
436
+ ok {curr_branch()} == "#{br}x"
437
+ output, sout = main "branch:echo", "PARENT"
438
+ ok {sout} == <<~'END'
439
+ [gi]$ git show-branch -a | sed 's/].*//' | grep '\*' | grep -v "\\[$(git branch --show-current)\$" | head -n1 | sed 's/^.*\[//'
440
+ br6488
441
+ END
442
+ ok {output} == ""
443
+ end
444
+ spec "print other branch name if other argument is specified." do
445
+ br = "br6490"
446
+ system! "git checkout -q -b #{br}"
447
+ output, sout = main "branch:echo", "HEAD"
448
+ ok {sout} == "[gi]$ git rev-parse --abbrev-ref HEAD\n"
449
+ ok {output} == "br6490\n"
450
+ #
451
+ output, sout, serr, status = main! "branch:echo", "current", tty: true
452
+ ok {unesc(sout)} == "[gi]$ git rev-parse --abbrev-ref current\n"
453
+ ok {serr} == <<~"END"
454
+ \e[31m[ERROR]\e[0m Git command failed: git rev-parse --abbrev-ref current
455
+ END
456
+ ok {output} == <<~'END'
457
+ fatal: ambiguous argument 'current': unknown revision or path not in the working tree.
458
+ Use '--' to separate paths from revisions, like this:
459
+ 'git <command> [<revision>...] -- [<file>...]'
460
+ current
461
+ END
462
+ end
463
+ end
464
+
465
+ }
466
+
467
+
468
+ topic('commit:') {
469
+
470
+ topic 'commit:apply' do
471
+ before do
472
+ _reset_all_commits()
473
+ end
474
+ def _prepare(br, file)
475
+ dummy_file(file, "A\nB\nC\nD\nE\n")
476
+ system! "git add #{file}"
477
+ system! "git commit -q -m 'add #{file}'"
478
+ system! "git checkout -q -b #{br}"
479
+ writefile(file, "A\nB\nC\nD\nE\nF\n") # append F
480
+ system! "git add -u ."
481
+ system! "git commit -q -m 'append F'"
482
+ writefile(file, "A\nB\nT\nD\nE\nF\n") # replace C with T
483
+ system! "git add -u ."
484
+ system! "git commit -q -m 'replace C with T'"
485
+ @commit_id = `git rev-parse HEAD`[0..6]
486
+ writefile(file, "A\nB\nT\nD\nE\nF\nG\n") # append G
487
+ system! "git add -u ."
488
+ system! "git commit -q -m 'append G'"
489
+ end
490
+ spec "apply a commit to curr branch (known as 'cherry-pick')" do
491
+ br = "br7479"
492
+ file = "file2214.txt"
493
+ _prepare(br, file)
494
+ #
495
+ system! "git checkout -q main"
496
+ _, sout = main "commit:apply", @commit_id
497
+ ok {sout} == "[gi]$ git cherry-pick #{@commit_id}\n"
498
+ ok {`git log --oneline`} =~ partial_regexp(<<~"END")
499
+ {==\\h{7}==} replace C with T
500
+ {==\\h{7}==} add #{file}
501
+ {==\\h{7}==} Initial commit (empty)
502
+ END
503
+ ok {readfile(file)} == "A\nB\nT\nD\nE\n" # C is replaced with T
504
+ end
505
+ end
506
+
507
+ topic 'commit:correct' do
508
+ before do
509
+ _reset_all_commits()
510
+ end
511
+ spec "correct the last commit" do
512
+ file = "file4043.txt"
513
+ dummy_file(file, "A\nB\n")
514
+ system! "git add #{file}"
515
+ system! "git commit -q -m 'add #{file}'"
516
+ #
517
+ writefile(file, "A\nB\nC\n")
518
+ system! "git add -u ."
519
+ commit_id = `git rev-parse HEAD`
520
+ output, sout = main "commit:correct", "-M"
521
+ ok {sout} == "[gi]$ git commit --amend --no-edit\n"
522
+ ok {output} =~ /^ 1 file changed, 3 insertions\(\+\)$/
523
+ ok {`git rev-parse HEAD`} != commit_id
524
+ ok {`git log -1 --oneline`} =~ /\A\h{7} add #{file}\n\z/
525
+ end
526
+ end
527
+
528
+ topic 'commit:create' do
529
+ spec "create a new commit" do
530
+ file = "file9247.txt"
531
+ dummy_file(file, "A\nB\n")
532
+ system! "git add #{file}"
533
+ output, sout = main "commit:create", "add '#{file}'"
534
+ ok {sout} == "[gi]$ git commit -m \"add '#{file}'\"\n"
535
+ ok {output} =~ /^ 1 file changed, 2 insertions\(\+\)$/
536
+ ok {`git log -1 --oneline`} =~ /\A\h{7} add '#{file}'\n\z/
537
+ end
538
+ end
539
+
540
+ topic 'commit:fixup' do
541
+ def _prepare(file1, file2)
542
+ dummy_file(file1, "A\nB\n")
543
+ system! "git add #{file1}"
544
+ system! "git commit -q -m \"add '#{file1}'\""
545
+ @commit_id = `git rev-parse HEAD`[0..6]
546
+ dummy_file(file2, "X\nY\n")
547
+ system! "git add #{file2}"
548
+ system! "git commit -q -m \"add '#{file2}'\""
549
+ end
550
+ spec "correct the previous commit" do
551
+ file = "file4150"
552
+ file1 = file + "xx"
553
+ file2 = file + "yy"
554
+ _prepare(file1, file2)
555
+ #
556
+ writefile(file1, "A\nB\nC\n")
557
+ system! "git add #{file1}"
558
+ output, sout = main "commit:fixup", @commit_id
559
+ ok {sout} == "[gi]$ git commit --fixup=#{@commit_id}\n"
560
+ ok {output} =~ /\[main \h{7}\] fixup! add '#{file1}'/
561
+ ok {`git log -3 --oneline`} =~ partial_regexp(<<~"END")
562
+ {==\\h{7}==} fixup! add '#{file1}'
563
+ {==\\h{7}==} add '#{file2}'
564
+ {==\\h{7}==} add '#{file1}'
565
+ END
566
+ end
567
+ end
568
+
569
+ topic 'commit:revert' do
570
+ def _prepare(file1, file2)
571
+ dummy_file(file1, "A\nB\n")
572
+ system! "git add #{file1}"
573
+ system! "git commit -q -m \"add '#{file1}'\""
574
+ #
575
+ dummy_file(file2, "X\nY\n")
576
+ system! "git add #{file2}"
577
+ system! "git commit -q -m \"add '#{file2}'\""
578
+ end
579
+ spec "create a new commit which reverts the target commit" do
580
+ file = "file3518"
581
+ file1 = file + "xx"
582
+ file2 = file + "yy"
583
+ _prepare(file1, file2)
584
+ commit_id = `git rev-parse HEAD^`[0..6]
585
+ #
586
+ output, sout = main "commit:revert", commit_id, "-M"
587
+ ok {sout} == "[gi]$ git revert --no-edit #{commit_id}\n"
588
+ ok {output} =~ /\A\[main \h{7}\] Revert "add '#{file1}'"$/
589
+ ok {`git log -3 --oneline`} =~ partial_regexp(<<~"END")
590
+ {==\\h{7}==} Revert "add '#{file1}'"
591
+ {==\\h{7}==} add '#{file2}'
592
+ {==\\h{7}==} add '#{file1}'
593
+ END
594
+ end
595
+ end
596
+
597
+ topic 'commit:rollback' do
598
+ def _prepare(file)
599
+ dummy_file(file, "A\n")
600
+ system! "git add #{file}"
601
+ system! "git commit -q -m 'add #{file}'"
602
+ #
603
+ writefile(file, "A\nB\n")
604
+ system! "git add #{file}"
605
+ system! "git commit -q -m 'append B'"
606
+ #
607
+ writefile(file, "A\nB\nC\n")
608
+ system! "git add #{file}"
609
+ system! "git commit -q -m 'append C'"
610
+ #
611
+ writefile(file, "A\nB\nC\nD\n")
612
+ system! "git add #{file}"
613
+ system! "git commit -q -m 'append D'"
614
+ end
615
+ spec "cancel recent commits up to the target commit-id" do
616
+ file = "file0710.txt"
617
+ _prepare(file)
618
+ #
619
+ ok {`git log -4 --oneline`} =~ partial_regexp(<<~"END")
620
+ {==\\h{7}==} append D
621
+ {==\\h{7}==} append C
622
+ {==\\h{7}==} append B
623
+ {==\\h{7}==} add #{file}
624
+ END
625
+ #
626
+ output, sout = main "commit:rollback", "-n2"
627
+ ok {sout} == "[gi]$ git reset \"HEAD~2\"\n"
628
+ ok {output} =~ /^M\t#{file}$/
629
+ ok {`git log -2 --oneline`} =~ partial_regexp(<<~"END")
630
+ {==\\h{7}==} append B
631
+ {==\\h{7}==} add #{file}
632
+ END
633
+ #
634
+ output, sout = main "commit:rollback"
635
+ ok {sout} == "[gi]$ git reset HEAD^\n"
636
+ ok {output} =~ /^M\t#{file}$/
637
+ ok {`git log -1 --oneline`} =~ partial_regexp(<<~"END")
638
+ {==\\h{7}==} add #{file}
639
+ END
640
+ end
641
+ end
642
+
643
+ topic 'commit:show' do
644
+ def _prepare(file)
645
+ dummy_file(file, "A\n")
646
+ system! "git add #{file}"
647
+ system! "git commit -q -m 'add #{file}'"
648
+ #
649
+ writefile(file, "A\nB\n")
650
+ system! "git add #{file}"
651
+ system! "git commit -q -m 'append B'"
652
+ #
653
+ writefile(file, "A\nB\nC\n")
654
+ system! "git add #{file}"
655
+ system! "git commit -q -m 'append C'"
656
+ #
657
+ writefile(file, "A\nB\nC\nD\n")
658
+ system! "git add #{file}"
659
+ system! "git commit -q -m 'append D'"
660
+ end
661
+ spec "show commits in current branch" do
662
+ file = "file2610.tmp"
663
+ _prepare(file)
664
+ commit_id = `git rev-parse HEAD^^`.strip()[0..6]
665
+ output, sout = main "commit:show", "-n1", commit_id
666
+ ok {sout} == <<~"END"
667
+ [gi]$ git show "#{commit_id}~1..#{commit_id}"
668
+ END
669
+ ok {output} =~ partial_regexp(<<~"END")
670
+ commit {==\\h{40}==}
671
+ Author: user1 <user1@gmail.com>
672
+ Date: {==.*==}
673
+
674
+ append B
675
+
676
+ diff --git a/#{file} b/#{file}
677
+ index {==\\h{7}==}..{==\\h{7}==} {==\\d+==}
678
+ --- a/#{file}
679
+ +++ b/#{file}
680
+ @@ -1 +1,2 @@
681
+ A
682
+ +B
683
+ END
684
+ end
685
+ spec "option '-n <N>' specifies the number of commits." do
686
+ file = "file9485.txt"
687
+ _prepare(file)
688
+ #
689
+ output, sout = main "commit:show", "-n1"
690
+ ok {sout} == <<~"END"
691
+ [gi]$ git show "HEAD~1..HEAD"
692
+ END
693
+ ok {output} =~ partial_regexp(<<~"END")
694
+ commit {==\\h{40}==}
695
+ Author: user1 <user1@gmail.com>
696
+ Date: {==.*==}
697
+
698
+ append D
699
+
700
+ diff --git a/#{file} b/#{file}
701
+ index {==\\h{7}==}..{==\\h{7}==} {==\\d+==}
702
+ --- a/#{file}
703
+ +++ b/#{file}
704
+ @@ -1,3 +1,4 @@
705
+ A
706
+ B
707
+ C
708
+ +D
709
+ END
710
+ #
711
+ output, sout = main "commit:show", "-n2"
712
+ ok {sout} == <<~"END"
713
+ [gi]$ git show "HEAD~2..HEAD"
714
+ END
715
+ ok {output} =~ partial_regexp(<<~"END")
716
+ commit {==\\h{40}==}
717
+ Author: user1 <user1@gmail.com>
718
+ Date: {==.*==}
719
+
720
+ append D
721
+
722
+ diff --git a/#{file} b/#{file}
723
+ index {==\\h{7}==}..{==\\h{7}==} {==\\d+==}
724
+ --- a/#{file}
725
+ +++ b/#{file}
726
+ @@ -1,3 +1,4 @@
727
+ A
728
+ B
729
+ C
730
+ +D
731
+
732
+ commit {==\\h{40}==}
733
+ Author: user1 <user1@gmail.com>
734
+ Date: {==.*==}
735
+
736
+ append C
737
+
738
+ diff --git a/#{file} b/#{file}
739
+ index {==\\h{7}==}..{==\\h{7}==} {==\\d+==}
740
+ --- a/#{file}
741
+ +++ b/#{file}
742
+ @@ -1,2 +1,3 @@
743
+ A
744
+ B
745
+ +C
746
+ END
747
+ end
748
+ end
749
+
750
+ }
751
+
752
+
753
+ topic('config:') {
754
+
755
+ topic 'config' do
756
+ spec "list/get/set/delete config values" do
757
+ at_end { system! "git config user.name user1" }
758
+ ## list
759
+ output, sout = main "config"
760
+ ok {sout} == <<~'END'
761
+ [gi]$ git config --list
762
+ END
763
+ ok {output} =~ /^user\.name=user1$/
764
+ ok {output} =~ /^user\.email=user1@gmail\.com$/
765
+ ## get
766
+ output, sout = main "config", "user.name"
767
+ ok {sout} == <<~'END'
768
+ [gi]$ git config user.name
769
+ END
770
+ ok {output} == "user1\n"
771
+ ## set
772
+ output, sout = main "config", "user.name", "user2"
773
+ ok {sout} == <<~'END'
774
+ [gi]$ git config user.name user2
775
+ END
776
+ ok {output} == ""
777
+ ok {`git config --get user.name`} == "user2\n"
778
+ ## delete
779
+ output, sout = main "config", "user.name", ""
780
+ ok {sout} == <<~'END'
781
+ [gi]$ git config --unset user.name
782
+ END
783
+ ok {output} == ""
784
+ ok {`git config --local --get user.name`} == ""
785
+ end
786
+ spec "filters by prefix if key is like 'foo.'." do
787
+ output, sout = main "config", "core."
788
+ ok {sout}.start_with?("[gi]$ git config -l | grep '^core\\.'\n")
789
+ ok {sout} =~ /^core\.pager=/
790
+ ok {sout} =~ /^core\.editor=/
791
+ lines = sout.each_line.to_a()
792
+ lines.shift()
793
+ ok {lines}.all? {|line| line.start_with?("core.") }
794
+ ok {output} == ""
795
+ end
796
+ spec "lists top level prefixes if key is '.'." do
797
+ output, sout = main "config", "."
798
+ ok {sout}.start_with?("[gi]$ gi config | awk -F. 'NR>1{d[$1]++}END{for(k in d){print(k\"\\t(\"d[k]\")\")}}' | sort\n")
799
+ ok {sout} =~ /^core\.\t\(\d+\)/
800
+ ok {sout} =~ /^user\.\t\(\d+\)/
801
+ end
802
+ end
803
+
804
+ topic 'config:alias' do
805
+ spec "list/get/set/delete aliases of 'git' (not of 'gi')" do
806
+ ## list
807
+ output, sout = main "config:alias"
808
+ ok {sout}.start_with?(<<~'END')
809
+ [gi]$ git config --get-regexp '^alias\.' | sed -e 's/^alias\.//;s/ /\t= /'
810
+ END
811
+ lines = sout.each_line().to_a()
812
+ lines.shift()
813
+ ok {lines}.all? {|line| line =~ /^\S+\t= .*/ }
814
+ ok {output} == ""
815
+ ## set
816
+ output, sout = main "config:alias", "br", "checkout -b"
817
+ ok {sout} == <<~'END'
818
+ [gi]$ git config --global alias.br "checkout -b"
819
+ END
820
+ ok {output} == ""
821
+ ## get
822
+ output, sout = main "config:alias", "br"
823
+ ok {sout} == <<~'END'
824
+ [gi]$ git config --global alias.br
825
+ END
826
+ ok {output} == "checkout -b\n"
827
+ ## delete
828
+ ok {`git config --get alias.br`} == "checkout -b\n"
829
+ ok {`git config --list`} =~ /^alias\.br=/
830
+ output, sout = main "config:alias", "br", ""
831
+ ok {sout} == <<~'END'
832
+ [gi]$ git config --global --unset alias.br
833
+ END
834
+ ok {output} == ""
835
+ ok {`git config --get alias.br`} == ""
836
+ ok {`git config --list`} !~ /^alias\.br=/
837
+ end
838
+ end
839
+
840
+ topic 'config:setuser' do
841
+ spec "set user name and email" do
842
+ at_end {
843
+ system! "git config user.name user1"
844
+ system! "git config user.email user1@gmail.com"
845
+ }
846
+ ## user and email
847
+ output, sout = main "config:setuser", "user6", "user6@gmail.com"
848
+ ok {sout}.start_with?(<<~'END')
849
+ [gi]$ git config user.name user6
850
+ [gi]$ git config user.email user6@gmail.com
851
+ END
852
+ ok {output} == ""
853
+ ok {`git config --get user.name`} == "user6\n"
854
+ ok {`git config --get user.email`} == "user6@gmail.com\n"
855
+ ## user
856
+ output, sout = main "config:setuser", "user7"
857
+ ok {sout}.start_with?(<<~'END')
858
+ [gi]$ git config user.name user7
859
+ END
860
+ ok {output} == ""
861
+ ok {`git config --get user.name`} == "user7\n"
862
+ ok {`git config --get user.email`} == "user6@gmail.com\n"
863
+ ## email
864
+ output, sout = main "config:setuser", "user8@gmail.com"
865
+ ok {sout}.start_with?(<<~'END')
866
+ [gi]$ git config user.email user8@gmail.com
867
+ END
868
+ ok {output} == ""
869
+ ok {`git config --get user.name`} == "user7\n"
870
+ ok {`git config --get user.email`} == "user8@gmail.com\n"
871
+ ## '-'
872
+ output, sout = main "config:setuser", "-", "user9@gmail.com"
873
+ ok {sout}.start_with?(<<~'END')
874
+ [gi]$ git config user.email user9@gmail.com
875
+ END
876
+ ok {output} == ""
877
+ ok {`git config --get user.name`} == "user7\n"
878
+ ok {`git config --get user.email`} == "user9@gmail.com\n"
879
+ end
880
+ end
881
+
882
+ }
883
+
884
+
885
+ topic('file:') {
886
+
887
+ topic 'file:changes' do
888
+ before do
889
+ system! "git reset -q --hard"
890
+ end
891
+ spec "show changes of files" do
892
+ file = "file1569.tmp"
893
+ dummy_file(file, "A\n")
894
+ system! "git add #{file}"
895
+ system! "git commit -q -m 'add #{file}'"
896
+ writefile(file, "A\nB\n")
897
+ output, sout = main "file:changes"
898
+ ok {sout} == "[gi]$ git diff\n"
899
+ ok {output} =~ partial_regexp(<<~"END")
900
+ diff --git a/#{file} b/#{file}
901
+ index {==\\h{7}==}..{==\\h{7}==} {==\\d+==}
902
+ --- a/#{file}
903
+ +++ b/#{file}
904
+ @@ -1 +1,2 @@
905
+ A
906
+ +B
907
+ END
908
+ end
909
+ end
910
+
911
+ topic 'file:delete' do
912
+ spec "delete files or directories" do
913
+ file = "file7807.tmp"
914
+ dummy_file(file, "A\n")
915
+ system! "git add #{file}"
916
+ system! "git commit -q -m 'add #{file}'"
917
+ ok {file}.file_exist?
918
+ output, sout = main "file:delete", file
919
+ ok {sout} == "[gi]$ git rm #{file}\n"
920
+ ok {output} == "rm 'file7807.tmp'\n"
921
+ ok {file}.not_exist?
922
+ end
923
+ end
924
+
925
+ topic 'file:list' do
926
+ before do
927
+ _reset_all_commits()
928
+ end
929
+ spec "list (un)tracked/ignored/missing files" do
930
+ file1 = "file1154.txt"
931
+ file2 = "file1154.css"
932
+ file3 = "file1154.json"
933
+ file4 = "file1154.json~"
934
+ dummy_file(file1, "A\n")
935
+ dummy_file(file2, "B\n")
936
+ dummy_file(file3, "C\n")
937
+ dummy_file(file4, "C\n")
938
+ system! "git add #{file1}"
939
+ system! "git add #{file2}"
940
+ system! "git commit -q -m 'add #{file1} and #{file2}'"
941
+ writefile(".gitignore", "*~\n")
942
+ at_end { rm_rf ".gitignore" }
943
+ ## tracked
944
+ output, sout = main "file:list"
945
+ ok {sout} == "[gi]$ git ls-files .\n"
946
+ ok {output} == <<~'END'
947
+ file1154.css
948
+ file1154.txt
949
+ END
950
+ ## untracked
951
+ output, sout = main "file:list", "-F", "untracked"
952
+ ok {sout} == <<~'END'
953
+ [gi]$ git status -s . | grep '^?? '
954
+ ?? .gitignore
955
+ ?? file1154.json
956
+ END
957
+ ok {output} == ""
958
+ ## ignored
959
+ output, sout = main "file:list", "-F", "ignored"
960
+ ok {sout} == <<~'END'
961
+ [gi]$ git status -s --ignored . | grep '^!! '
962
+ !! file1154.json~
963
+ END
964
+ ok {output} == ""
965
+ ## missing
966
+ File.unlink(file1)
967
+ output, sout = main "file:list", "-F", "missing"
968
+ ok {sout} == <<~'END'
969
+ [gi]$ git ls-files --deleted .
970
+ END
971
+ ok {output} == <<~"END"
972
+ file1154.txt
973
+ END
974
+ end
975
+ end
976
+
977
+ topic 'file:move' do
978
+ spec "move files into a directory" do
979
+ file1 = "file3304.css"
980
+ file2 = "file3304.js"
981
+ file3 = "file3304.html"
982
+ dir = "file3304.d"
983
+ dummy_file(file1, "A\n")
984
+ dummy_file(file2, "B\n")
985
+ dummy_file(file3, "C\n")
986
+ dummy_dir(dir)
987
+ system! "git add #{file1} #{file2} #{file3}"
988
+ system! "git commit -q -m 'add #{file1}, #{file2} and #{file3}'"
989
+ #
990
+ output, sout = main "file:move", file1, file3, "--to=#{dir}"
991
+ ok {sout} == "[gi]$ git mv #{file1} #{file3} #{dir}\n"
992
+ ok {output} == ""
993
+ ok {file1}.not_exist?
994
+ ok {file2}.file_exist?
995
+ ok {file3}.not_exist?
996
+ end
997
+ end
998
+
999
+ topic 'file:track' do
1000
+ spec "track files into the repository" do
1001
+ file = "file2717.tmp"
1002
+ dummy_file(file, "A\n")
1003
+ #
1004
+ ok {`git ls-files .`} !~ /^#{file}$/
1005
+ output, sout = main "file:track", file
1006
+ ok {sout} == "[gi]$ git add #{file}\n"
1007
+ ok {output} == ""
1008
+ ok {`git ls-files .`} =~ /^#{file}$/
1009
+ end
1010
+ end
1011
+
1012
+ topic 'file:rename' do
1013
+ spec "rename a file or directory to new name" do
1014
+ file = "file3365.tmp"
1015
+ dummy_file(file, "A\n")
1016
+ system! "git add #{file}"
1017
+ system! "git commit -q -m 'add #{file}'"
1018
+ #
1019
+ ok {file}.file_exist?
1020
+ ok {file+".bkup"}.not_exist?
1021
+ output, sout = main "file:rename", file, file+".bkup"
1022
+ ok {sout} == "[gi]$ git mv #{file} #{file}.bkup\n"
1023
+ ok {output} == ""
1024
+ ok {file}.not_exist?
1025
+ ok {file+".bkup"}.file_exist?
1026
+ end
1027
+ end
1028
+
1029
+ topic 'file:restore' do
1030
+ before do
1031
+ system! "git reset -q --hard HEAD"
1032
+ end
1033
+ spec "restore files (= clear changes)" do
1034
+ file = "file2908.txt"
1035
+ dummy_file(file, "A\n")
1036
+ system! "git add #{file}"
1037
+ system! "git commit -q -m 'add #{file}'"
1038
+ writefile(file, "A\nB\n")
1039
+ ok {`git diff`} =~ partial_regexp(<<~"END")
1040
+ diff --git a/file2908.txt b/file2908.txt
1041
+ index {==\\h{7}==}..{==\\h{7}==} {==\\d+==}
1042
+ --- a/file2908.txt
1043
+ +++ b/file2908.txt
1044
+ @@ -1 +1,2 @@
1045
+ A
1046
+ +B
1047
+ END
1048
+ #
1049
+ output, sout = main "file:restore"
1050
+ ok {sout} == "[gi]$ git reset --hard\n"
1051
+ ok {output} =~ partial_regexp(<<~"END")
1052
+ HEAD is now at {==\\h{7}==} add #{file}
1053
+ END
1054
+ ok {`git diff`} == ""
1055
+ end
1056
+ end
1057
+
1058
+ topic 'file:blame' do
1059
+ def _prepare(file)
1060
+ dummy_file(file, "AAA\n")
1061
+ system! "git add #{file}"
1062
+ system! "git commit -q -m 'add #{file}'"
1063
+ writefile(file, "AAA\nBBB\n")
1064
+ system! "git commit -q -m 'update #{file}' #{file}"
1065
+ end
1066
+ spec "print commit-id, author, and timestap of each line" do
1067
+ file = "file2726"
1068
+ _prepare(file)
1069
+ output, sout = main "file:blame", file
1070
+ ok {sout} == "[gi]$ git blame file2726\n"
1071
+ ok {output} =~ partial_regexp(<<~'END')
1072
+ {==\h{8}==} (user1 {==.*==} 1) AAA
1073
+ {==\h{8}==} (user1 {==.*==} 2) BBB
1074
+ END
1075
+ end
1076
+ end
1077
+
1078
+ topic 'file:egrep' do
1079
+ spec "find by pattern" do
1080
+ file = "file0154"
1081
+ dummy_file(file, "AAA7706\nBBB7706\nCCC7706\n")
1082
+ system! "git add #{file}"
1083
+ system! "git commit -q -m 'add #{file}'"
1084
+ output, sout = main "file:egrep", "B+7706", "HEAD"
1085
+ ok {sout} == "[gi]$ git grep -E B+7706 HEAD\n"
1086
+ ok {output} == "HEAD:file0154:BBB7706\n"
1087
+ end
1088
+ end
1089
+
1090
+ }
1091
+
1092
+
1093
+ topic('help') {
1094
+ spec "print help message (of action if specified)" do
1095
+ _, sout = main "help", tty: true
1096
+ ok {sout} == <<~"END"
1097
+ \e[1mgi\e[0m \e[2m(0.0.0)\e[0m --- Git Improved
1098
+
1099
+ \e[1;34mUsage:\e[0m
1100
+ $ \e[1mgi\e[0m [<options>] <action> [<arguments>...]
1101
+
1102
+ \e[1;34mOptions:\e[0m
1103
+ -h, --help : print help message (of action if specified)
1104
+ -V, --version : print version
1105
+ -l, --list : list actions and aliases
1106
+ -L <topic> : topic list (actions|aliases|categories|abbrevs)
1107
+ -a, --all : list hidden actions/options, too
1108
+ -q, --quiet : quiet mode
1109
+ --color[=<on|off>] : color mode
1110
+ -X, --dryrun : dry-run mode (not run; just echoback)
1111
+
1112
+ \e[1;34mActions:\e[0m
1113
+ (Too long to show. Run `gi -l` to list all actions.)
1114
+
1115
+ \e[1;34mExample:\e[0m
1116
+ $ mkdir mysample # or: gi repo:clone github:<user>/<repo>
1117
+ $ cd mysample
1118
+ $ gi repo:init -u yourname -e yourname@gmail.com
1119
+ $ vi README.md # create a new file
1120
+ $ gi track README.md # track files into the repository
1121
+ $ gi cc "add README file" # commit changes
1122
+ $ vi README.md # update an existing file
1123
+ $ gi stage . # add changes into staging area
1124
+ $ gi staged # show changes in staging area
1125
+ $ gi cc "update README file" # commit changes
1126
+ $ gi repo:remote:origin github:yourname/mysample # set remote repo
1127
+ $ gi push # upload local commits to remote repo
1128
+
1129
+ \e[1;34mDocument:\e[0m
1130
+ https://kwatch.github.io/git-improved/
1131
+ END
1132
+ end
1133
+ spec "prints help message of action if action name specified." do
1134
+ _, sout = main "help", "config", tty: true
1135
+ ok {sout} == <<~"END"
1136
+ \e[1mgi config\e[0m --- list/get/set/delete config values
1137
+
1138
+ \e[1;34mUsage:\e[0m
1139
+ $ \e[1mgi config\e[0m [<options>] # list
1140
+ $ \e[1mgi config\e[0m [<options>] <key> # get
1141
+ $ \e[1mgi config\e[0m [<options>] <key> <value> # set
1142
+ $ \e[1mgi config\e[0m [<options>] <key> "" # delete
1143
+ $ \e[1mgi config\e[0m [<options>] <prefix> # filter by prefix
1144
+
1145
+ \e[1;34mOptions:\e[0m
1146
+ -g, --global : handle global config
1147
+ -l, --local : handle repository local config
1148
+
1149
+ \e[1;34mExample:\e[0m
1150
+ $ gi config # list
1151
+ $ gi config core.editor # get
1152
+ $ gi config core.editor vim # set
1153
+ $ gi config core.editor "" # delete
1154
+ $ gi config core. # filter by prefix
1155
+ $ gi config . # list top level prefixes
1156
+ END
1157
+ end
1158
+ }
1159
+
1160
+
1161
+ topic('history:') {
1162
+
1163
+ def _prepare(basefile)
1164
+ file1 = "#{basefile}.rb"
1165
+ file2 = "#{basefile}.py"
1166
+ dummy_file(file1, "A\n")
1167
+ dummy_file(file2, "B\n")
1168
+ system! "git add #{file1}"
1169
+ system! "git commit -q -m 'add #{file1}'"
1170
+ system! "git add #{file2}"
1171
+ system! "git commit -q -m 'add #{file2}'"
1172
+ return file1, file2
1173
+ end
1174
+
1175
+ topic 'history:show' do
1176
+ before do
1177
+ _reset_all_commits()
1178
+ end
1179
+ spec "shows commit history in default format." do
1180
+ _test_default_format()
1181
+ end
1182
+ spec "option '-F default' shows commit history in default format." do
1183
+ _test_default_format("-F", "default")
1184
+ end
1185
+ def _test_default_format(*opts)
1186
+ file1, file2 = _prepare("file8460")
1187
+ output, sout = main "history", *opts
1188
+ ok {sout} == "[gi]$ git log\n"
1189
+ ok {output} =~ partial_regexp(<<~"END")
1190
+ commit {==\\h{40}==}
1191
+ Author: user1 <user1@gmail.com>
1192
+ Date: {==.*==}
1193
+
1194
+ add #{file2}
1195
+
1196
+ commit {==\\h{40}==}
1197
+ Author: user1 <user1@gmail.com>
1198
+ Date: {==.*==}
1199
+
1200
+ add #{file1}
1201
+
1202
+ commit {==\\h{40}==}
1203
+ Author: user1 <user1@gmail.com>
1204
+ Date: {==.*==}
1205
+
1206
+ Initial commit (empty)
1207
+ END
1208
+ end
1209
+ spec "option '-F fuller' shows commit history in detailed format." do
1210
+ file1, file2 = _prepare("file0632")
1211
+ output, sout = main "history", "-F", "fuller"
1212
+ ok {sout} == "[gi]$ git log --format=fuller\n"
1213
+ ok {output} =~ partial_regexp(<<~"END")
1214
+ commit {==\\h{40}==}
1215
+ Author: user1 <user1@gmail.com>
1216
+ AuthorDate: {==.*==}
1217
+ Commit: user1 <user1@gmail.com>
1218
+ CommitDate: {==.*==}
1219
+
1220
+ add #{file2}
1221
+
1222
+ commit {==\\h{40}==}
1223
+ Author: user1 <user1@gmail.com>
1224
+ AuthorDate: {==.*==}
1225
+ Commit: user1 <user1@gmail.com>
1226
+ CommitDate: {==.*==}
1227
+
1228
+ add #{file1}
1229
+
1230
+ commit {==\\h{40}==}
1231
+ Author: user1 <user1@gmail.com>
1232
+ AuthorDate: {==.*==}
1233
+ Commit: user1 <user1@gmail.com>
1234
+ CommitDate: {==.*==}
1235
+
1236
+ Initial commit (empty)
1237
+ END
1238
+ end
1239
+ spec "option '-F oneline' shows history in compact format." do
1240
+ file1, file2 = _prepare("file5624")
1241
+ output, sout = main "history", "-F", "oneline"
1242
+ ok {sout} == "[gi]$ git log --oneline\n"
1243
+ ok {output} =~ partial_regexp(<<~"END")
1244
+ {==\\h{7}==} add #{file2}
1245
+ {==\\h{7}==} add #{file1}
1246
+ {==\\h{7}==} Initial commit (empty)
1247
+ END
1248
+ end
1249
+ spec "option '-F graph' shows commit history with branch graph." do
1250
+ file1, file2 = _prepare("file6071")
1251
+ output, sout = main "history", "-F", "graph"
1252
+ ok {sout} == <<~"END"
1253
+ [gi]$ git log --format="%C(auto)%h %ad | %d %s" --graph --date=short --decorate
1254
+ END
1255
+ today = Time.now.strftime("%Y-%m-%d")
1256
+ ok {output} =~ partial_regexp(<<~"END")
1257
+ * {==\\h{7}==} #{today} | (HEAD -> main) add #{file2}
1258
+ * {==\\h{7}==} #{today} | add #{file1}
1259
+ * {==\\h{7}==} #{today} | {==(?:\(.*?\) )?==}Initial commit (empty)
1260
+ END
1261
+ end
1262
+ end
1263
+
1264
+ topic 'history:edit:cancel' do
1265
+ spec "cancel (or abort) `git rebase -i`" do
1266
+ ## TODO
1267
+ dryrun_mode do
1268
+ _, sout = main "history:edit:cancel"
1269
+ ok {sout} == "[gi]$ git rebase --abort\n"
1270
+ end
1271
+ end
1272
+ end
1273
+
1274
+ topic 'history:edit:resume' do
1275
+ spec "resume (= conitnue) suspended `git rebase -i`" do
1276
+ ## TODO
1277
+ dryrun_mode do
1278
+ _, sout = main "history:edit:resume"
1279
+ ok {sout} == "[gi]$ git rebase --continue\n"
1280
+ end
1281
+ end
1282
+ end
1283
+
1284
+ topic 'history:edit:skip' do
1285
+ spec "skip current commit and resume" do
1286
+ ## TODO
1287
+ dryrun_mode do
1288
+ _, sout = main "history:edit:skip"
1289
+ ok {sout} == "[gi]$ git rebase --skip\n"
1290
+ end
1291
+ end
1292
+ end
1293
+
1294
+ topic 'history:edit:start' do
1295
+ spec "start `git rebase -i` to edit commit history" do
1296
+ ## TODO
1297
+ dryrun_mode do
1298
+ _, sout = main "history:edit:start", "-n2"
1299
+ ok {sout} == "[gi]$ git rebase -i --autosquash \"HEAD~2\"\n"
1300
+ end
1301
+ end
1302
+ end
1303
+
1304
+ topic 'history:notuploaded' do
1305
+ spec "show commits not uploaded yet" do
1306
+ ## TODO
1307
+ dryrun_mode do
1308
+ _, sout = main "history:notuploaded"
1309
+ ok {sout} == "[gi]$ git cherry -v\n"
1310
+ end
1311
+ end
1312
+ end
1313
+
1314
+ }
1315
+
1316
+
1317
+ topic('misc:') {
1318
+
1319
+ topic 'misc:initfile' do
1320
+ spec "generate a setup file" do
1321
+ file = "file1533.rb"
1322
+ at_end { rm_rf file }
1323
+ ok {file}.not_exist?
1324
+ _, sout = main "misc:initfile", file
1325
+ ok {sout} == "[OK] file1533.rb generated.\n"
1326
+ ok {file}.file_exist?
1327
+ ok {readfile(file)} =~ /def hello\(name="world", lang: "en"\)/
1328
+ ok {`ruby -wc #{file}`} == "Syntax OK\n"
1329
+ end
1330
+ spec "print to stdout if no args" do
1331
+ [[], ["-"]].each do |args|
1332
+ _, sout = main "misc:initfile", *args
1333
+ ok {sout} =~ /def hello\(name="world", lang: "en"\)/
1334
+ file = dummy_file(nil, sout)
1335
+ ok {`ruby -wc #{file}`} == "Syntax OK\n"
1336
+ end
1337
+ end
1338
+ end
1339
+
1340
+ }
1341
+
1342
+
1343
+ topic('repo:') {
1344
+
1345
+ topic 'repo:clone' do
1346
+ spec "copy a repository ('github:<user>/<repo>' is available)" do
1347
+ ## TODO
1348
+ dir = "repo7594"
1349
+ at_end { rm_rf dir }
1350
+ Dir.mkdir dir
1351
+ Dir.chdir dir do
1352
+ dryrun_mode do
1353
+ url = "github:user3/repo3"
1354
+ args = ["-u", "user1", "-e", "user1@gmail.com"]
1355
+ output, sout = main "repo:clone", url, *args, dir
1356
+ ok {sout} == <<~"END"
1357
+ [gi]$ git clone git@github.com:user3/repo3.git #{dir}
1358
+ [gi]$ cd #{dir}
1359
+ [gi]$ git config user.name user1
1360
+ [gi]$ git config user.email user1@gmail.com
1361
+ [gi]$ cd -
1362
+ END
1363
+ ok {output} == ""
1364
+ end
1365
+ end
1366
+ end
1367
+ end
1368
+
1369
+ topic 'repo:create' do
1370
+ spec "create a new directory and initialize it as a git repo" do
1371
+ dir = "repo1364"
1372
+ at_end { rm_rf dir }
1373
+ ok {dir}.not_exist?
1374
+ _, sout = main "repo:create", dir, "-uuser1", "-ename1@gmail.com"
1375
+ ok {sout} == <<~'END'
1376
+ [gi]$ mkdir repo1364
1377
+ [gi]$ cd repo1364
1378
+ [gi]$ git init --initial-branch=main
1379
+ [gi]$ git config user.name user1
1380
+ [gi]$ git config user.email name1@gmail.com
1381
+ [gi]$ git commit --allow-empty -m "Initial commit (empty)"
1382
+ [gi]$ echo '*~' > .gitignore
1383
+ [gi]$ echo '*.DS_Store' >> .gitignore
1384
+ [gi]$ echo 'tmp' >> .gitignore
1385
+ [gi]$ echo '*.pyc' >> .gitignore
1386
+ [gi]$ cd -
1387
+ END
1388
+ ok {dir}.dir_exist?
1389
+ end
1390
+ end
1391
+
1392
+ topic 'repo:init' do
1393
+ spec "initialize git repository with empty initial commit" do
1394
+ dir = "repo4984"
1395
+ at_end { rm_rf dir }
1396
+ Dir.mkdir dir
1397
+ Dir.chdir dir do
1398
+ ok {".git"}.not_exist?
1399
+ _, sout = main "repo:init", "-uuser1", "-euser1@gmail.com"
1400
+ ok {sout} == <<~'END'
1401
+ [gi]$ git init --initial-branch=main
1402
+ [gi]$ git config user.name user1
1403
+ [gi]$ git config user.email user1@gmail.com
1404
+ [gi]$ git commit --allow-empty -m "Initial commit (empty)"
1405
+ [gi]$ echo '*~' > .gitignore
1406
+ [gi]$ echo '*.DS_Store' >> .gitignore
1407
+ [gi]$ echo 'tmp' >> .gitignore
1408
+ [gi]$ echo '*.pyc' >> .gitignore
1409
+ END
1410
+ ok {".git"}.dir_exist?
1411
+ end
1412
+ end
1413
+ end
1414
+
1415
+ topic 'repo:remote' do
1416
+ spec "list/get/set/delete remote repository" do
1417
+ ## list (empty)
1418
+ output, sout = main "repo:remote"
1419
+ ok {sout} == "[gi]$ git remote -v\n"
1420
+ ok {output} == ""
1421
+ ## set (add)
1422
+ output, sout = main "repo:remote", "origin", "github:user1/repo1"
1423
+ ok {sout} == <<~"END"
1424
+ [gi]$ git remote add origin git@github.com:user1/repo1.git
1425
+ END
1426
+ ok {output} == ""
1427
+ ## get
1428
+ output, sout = main "repo:remote", "origin"
1429
+ ok {sout} == "[gi]$ git remote get-url origin\n"
1430
+ ok {output} == "git@github.com:user1/repo1.git\n"
1431
+ ## set
1432
+ output, sout = main "repo:remote", "origin", "gitlab:user2/repo2"
1433
+ ok {sout} == <<~"END"
1434
+ [gi]$ git remote set-url origin git@gitlab.com:user2/repo2.git
1435
+ END
1436
+ ok {output} == ""
1437
+ ## list
1438
+ output, sout = main "repo:remote"
1439
+ ok {sout} == "[gi]$ git remote -v\n"
1440
+ ok {output} == <<~"END"
1441
+ origin git@gitlab.com:user2/repo2.git (fetch)
1442
+ origin git@gitlab.com:user2/repo2.git (push)
1443
+ END
1444
+ ## delete
1445
+ output, sout = main "repo:remote", "origin", ""
1446
+ ok {sout} == "[gi]$ git remote remove origin\n"
1447
+ ok {output} == ""
1448
+ ## list (empty)
1449
+ output, sout = main "repo:remote"
1450
+ ok {sout} == "[gi]$ git remote -v\n"
1451
+ ok {output} == ""
1452
+ end
1453
+ end
1454
+
1455
+ topic 'repo:remote:origin' do
1456
+ spec "get/set/delete origin (= default remote repository)" do
1457
+ ## get (empty)
1458
+ output, sout, serr, status = main! "repo:remote:origin", tty: true
1459
+ ok {status} != 0
1460
+ ok {unesc(sout)} == "[gi]$ git remote get-url origin\n"
1461
+ ok {serr} == "\e[31m[ERROR]\e[0m Git command failed: git remote get-url origin\n"
1462
+ ok {output} == "error: No such remote 'origin'\n"
1463
+ ## set (add)
1464
+ output, sout = main "repo:remote:origin", "github:user1/repo1"
1465
+ ok {sout} == <<~"END"
1466
+ [gi]$ git remote add origin git@github.com:user1/repo1.git
1467
+ END
1468
+ ok {output} == ""
1469
+ ## get
1470
+ output, sout = main "repo:remote:origin"
1471
+ ok {sout} == "[gi]$ git remote get-url origin\n"
1472
+ ok {output} == "git@github.com:user1/repo1.git\n"
1473
+ ## set
1474
+ output, sout = main "repo:remote:origin", "gitlab:user2/repo2"
1475
+ ok {sout} == <<~"END"
1476
+ [gi]$ git remote set-url origin git@gitlab.com:user2/repo2.git
1477
+ END
1478
+ ok {output} == ""
1479
+ ## get
1480
+ output, sout = main "repo:remote:origin"
1481
+ ok {sout} == "[gi]$ git remote get-url origin\n"
1482
+ ok {output} == "git@gitlab.com:user2/repo2.git\n"
1483
+ ## delete
1484
+ output, sout = main "repo:remote:origin", ""
1485
+ ok {sout} == "[gi]$ git remote remove origin\n"
1486
+ ok {output} == ""
1487
+ ## get (empty)
1488
+ output, sout, serr, status = main! "repo:remote:origin", tty: true
1489
+ ok {status} != 0
1490
+ ok {unesc(sout)} == "[gi]$ git remote get-url origin\n"
1491
+ ok {serr} == "\e[31m[ERROR]\e[0m Git command failed: git remote get-url origin\n"
1492
+ ok {output} == "error: No such remote 'origin'\n"
1493
+ end
1494
+ end
1495
+
1496
+ }
1497
+
1498
+
1499
+ topic('staging:') {
1500
+
1501
+ topic 'staging:add' do
1502
+ before do
1503
+ _reset_all_commits()
1504
+ system! "git reset HEAD"
1505
+ end
1506
+ spec "add changes of files into staging area" do
1507
+ file = "file7198.txt"
1508
+ dummy_file file, "AAA\n"
1509
+ system! "git add #{file}"
1510
+ system! "git commit -q -m 'add #{file}'"
1511
+ system! "echo BBB >> #{file}"
1512
+ ok {`git diff --cached`} == ""
1513
+ output, sout = main "staging:add", "."
1514
+ ok {sout} == "[gi]$ git add -u .\n"
1515
+ ok {`git diff --cached`} =~ partial_regexp(<<~'END')
1516
+ diff --git a/file7198.txt b/file7198.txt
1517
+ index {==\h{7}==}..{==\h{7}==} {==\d+==}
1518
+ --- a/file7198.txt
1519
+ +++ b/file7198.txt
1520
+ @@ -1 +1,2 @@
1521
+ AAA
1522
+ +BBB
1523
+ END
1524
+ ok {output} == ""
1525
+ end
1526
+ end
1527
+
1528
+ topic 'staging:clear' do
1529
+ spec "delete all changes in staging area" do
1530
+ file = "file3415.txt"
1531
+ dummy_file file, "AAA\n"
1532
+ system! "git add #{file}"
1533
+ ok {`git diff --cached`} != ""
1534
+ _, sout = main "staging:clear"
1535
+ ok {sout} == "[gi]$ git reset HEAD\n"
1536
+ ok {`git diff --cached`} == ""
1537
+ end
1538
+ end
1539
+
1540
+ topic 'staging:edit' do
1541
+ spec "edit changes in staging area" do
1542
+ ## TODO
1543
+ dryrun_mode do
1544
+ _, sout = main "staging:edit"
1545
+ ok {sout} == "[gi]$ git add --edit\n"
1546
+ end
1547
+ end
1548
+ end
1549
+
1550
+ topic 'staging:show' do
1551
+ spec "show changes in staging area" do
1552
+ file = "file2794.txt"
1553
+ dummy_file file, "AAA\n"
1554
+ system! "git add #{file}"
1555
+ output, sout = main "staging:show"
1556
+ ok {sout} == "[gi]$ git diff --cached\n"
1557
+ ok {output} =~ partial_regexp(<<~'END')
1558
+ diff --git a/file2794.txt b/file2794.txt
1559
+ new file mode 100644
1560
+ index 0000000..{==\h{7}==}
1561
+ --- /dev/null
1562
+ +++ b/file2794.txt
1563
+ @@ -0,0 +1 @@
1564
+ +AAA
1565
+ END
1566
+ end
1567
+ end
1568
+
1569
+ }
1570
+
1571
+
1572
+ topic('stash:') {
1573
+
1574
+ after do
1575
+ system! "git stash clear"
1576
+ end
1577
+
1578
+ def dummy_stash1(file1)
1579
+ dummy_file file1, "AAA\n"
1580
+ system! "git add #{file1}"
1581
+ system! "git commit -q -m 'add #{file1}'"
1582
+ system! "echo BBB >> #{file1}"
1583
+ system! "git stash push -q"
1584
+ return file1
1585
+ end
1586
+
1587
+ def dummy_stash2(file2)
1588
+ dummy_file file2, "DDD\n"
1589
+ system! "git add #{file2}"
1590
+ system! "git commit -q -m 'add #{file2}'"
1591
+ system! "echo EEE >> #{file2}"
1592
+ system! "git stash push -q"
1593
+ return file2
1594
+ end
1595
+
1596
+ topic 'stash:drop' do
1597
+ spec "delete latest changes from stash" do
1598
+ file1 = dummy_stash1("file7294x.txt")
1599
+ file2 = dummy_stash2("file7294y.txt")
1600
+ ok {`git stash list`} =~ partial_regexp(<<~"END")
1601
+ stash@{0}: WIP on main: {==\\h{7}==} add #{file2}
1602
+ stash@{1}: WIP on main: {==\\h{7}==} add #{file1}
1603
+ END
1604
+ output, sout = main "stash:drop"
1605
+ ok {sout} == "[gi]$ git stash drop\n"
1606
+ ok {output} =~ /\ADropped refs\/stash@\{0\} \(\w+\)$/
1607
+ ok {`git stash list`} =~ partial_regexp(<<~"END")
1608
+ stash@{0}: WIP on main: {==\\h{7}==} add #{file1}
1609
+ END
1610
+ end
1611
+ end
1612
+
1613
+ topic 'stash:list' do
1614
+ spec "list stash history" do
1615
+ file1 = dummy_stash1("file3562x.txt")
1616
+ file2 = dummy_stash2("file3562y.txt")
1617
+ output, sout = main "stash:list"
1618
+ ok {sout} == "[gi]$ git stash list\n"
1619
+ ok {output} =~ partial_regexp(<<~"END")
1620
+ stash@{0}: WIP on main: {==\\h{7}==} add #{file2}
1621
+ stash@{1}: WIP on main: {==\\h{7}==} add #{file1}
1622
+ END
1623
+ end
1624
+ end
1625
+
1626
+ topic 'stash:pop' do
1627
+ spec "restore latest changes from stash" do
1628
+ file1 = dummy_stash1("file7779x.txt")
1629
+ file2 = dummy_stash2("file7779y.txt")
1630
+ ok {readfile(file1)} == "AAA\n"
1631
+ ok {readfile(file2)} == "DDD\n"
1632
+ #
1633
+ output, sout = main "stash:pop"
1634
+ ok {sout} == "[gi]$ git stash pop\n"
1635
+ ok {output} != ""
1636
+ ok {readfile(file1)} == "AAA\n"
1637
+ ok {readfile(file2)} == "DDD\nEEE\n"
1638
+ #
1639
+ output, sout = main "stash:pop"
1640
+ ok {sout} == "[gi]$ git stash pop\n"
1641
+ ok {output} != ""
1642
+ ok {readfile(file1)} == "AAA\nBBB\n"
1643
+ ok {readfile(file2)} == "DDD\nEEE\n"
1644
+ end
1645
+ end
1646
+
1647
+ topic 'stash:put' do
1648
+ spec "save current changes into stash" do
1649
+ file1 = dummy_stash1("file4591.txt")
1650
+ system! "git stash clear"
1651
+ ok {`git diff`} == ""
1652
+ system! "echo KKK >> #{file1}"
1653
+ ok {`git diff`} != ""
1654
+ ok {`git stash list`} == ""
1655
+ output, sout = main "stash:put"
1656
+ ok {sout} == "[gi]$ git stash push\n"
1657
+ ok {output} != ""
1658
+ ok {`git diff`} == ""
1659
+ ok {`git stash list`} =~ partial_regexp(<<~'END')
1660
+ stash@{0}: WIP on main: {==\h{7}==} add file4591.txt
1661
+ END
1662
+ end
1663
+ end
1664
+
1665
+ topic 'stash:show' do
1666
+ spec "show changes on stash" do
1667
+ _reset_all_commits() # !!!
1668
+ _file1 = dummy_stash1("file9510x.txt")
1669
+ file2 = dummy_stash2("file9510y.txt")
1670
+ expected_regexp = partial_regexp(<<~"END")
1671
+ diff --git a/#{file2} b/#{file2}
1672
+ index {==\\h{7}==}..{==\\h{7}==} {==\\d+==}
1673
+ --- a/#{file2}
1674
+ +++ b/#{file2}
1675
+ @@ -1 +1,2 @@
1676
+ DDD
1677
+ +EEE
1678
+ END
1679
+ #
1680
+ output, sout = main "stash:show"
1681
+ ok {sout} == <<~'END'
1682
+ [gi]$ git stash show -p
1683
+ END
1684
+ ok {output} =~ expected_regexp
1685
+ #
1686
+ output, sout = main "stash:show", "-n", "1"
1687
+ ok {sout} == "[gi]$ git stash show -p \"stash@{0}\"\n"
1688
+ ok {output} =~ expected_regexp
1689
+ #
1690
+ output, sout = main "stash:show", "-n2"
1691
+ ok {sout} == "[gi]$ git stash show -p \"stash@{1}\"\n"
1692
+ ok {output} =~ partial_regexp(<<~'END')
1693
+ diff --git a/file9510x.txt b/file9510x.txt
1694
+ index {==\h{7}==}..{==\h{7}==} {==\d+==}
1695
+ --- a/file9510x.txt
1696
+ +++ b/file9510x.txt
1697
+ @@ -1 +1,2 @@
1698
+ AAA
1699
+ +BBB
1700
+ END
1701
+ end
1702
+ end
1703
+
1704
+ }
1705
+
1706
+
1707
+ topic('status:') {
1708
+
1709
+ before do
1710
+ _reset_all_commits()
1711
+ #
1712
+ file1 = "file8040.txt" # tracked, modified
1713
+ file2 = "file8040.css" # tracked
1714
+ file3 = "file8040.html" # not tracked
1715
+ dummy_file(file1, "A\n")
1716
+ dummy_file(file2, "B\n")
1717
+ dummy_file(file3, "C\n")
1718
+ system! "git add #{file1} #{file2}"
1719
+ system! "git commit -q -m 'add #{file1} and #{file2}'"
1720
+ writefile(file1, "AA\n")
1721
+ @file1 = file1; @file2 = file2, @file3 = file3
1722
+ end
1723
+
1724
+ topic 'status:compact' do
1725
+ spec "show status in compact format" do
1726
+ output, sout = main "status:compact"
1727
+ ok {sout} == "[gi]$ git status -sb\n"
1728
+ ok {output} == <<~'END'
1729
+ ## main
1730
+ M file8040.txt
1731
+ ?? file8040.html
1732
+ END
1733
+ end
1734
+ end
1735
+
1736
+ topic 'status:default' do
1737
+ spec "show status in default format" do
1738
+ output, sout = main "status:default"
1739
+ ok {sout} == "[gi]$ git status\n"
1740
+ ok {output} == <<~'END'
1741
+ On branch main
1742
+ Changes not staged for commit:
1743
+ (use "git add <file>..." to update what will be committed)
1744
+ (use "git restore <file>..." to discard changes in working directory)
1745
+ modified: file8040.txt
1746
+
1747
+ Untracked files:
1748
+ (use "git add <file>..." to include in what will be committed)
1749
+ file8040.html
1750
+
1751
+ no changes added to commit (use "git add" and/or "git commit -a")
1752
+ END
1753
+ end
1754
+ end
1755
+
1756
+ topic 'status:here' do
1757
+ spec "same as 'stats:compact .'" do
1758
+ output, sout = main "status:here"
1759
+ ok {sout} == "[gi]$ git status -sb .\n"
1760
+ ok {output} == <<~'END'
1761
+ ## main
1762
+ M file8040.txt
1763
+ ?? file8040.html
1764
+ END
1765
+ end
1766
+ end
1767
+
1768
+ topic 'status:info' do
1769
+ spec "show various infomation of current status" do
1770
+ output, sout = main "status:info"
1771
+ ok {sout} == <<~'END'
1772
+ [gi]$ git status -sb . | sed -n 's!/$!!;/^??/s/^?? //p' | xargs ls -dF --color
1773
+ [gi]$ git status -sb -uno .
1774
+ END
1775
+ ok {output} == <<~'END'
1776
+ file8040.html
1777
+ ## main
1778
+ M file8040.txt
1779
+ END
1780
+ end
1781
+ end
1782
+
1783
+ }
1784
+
1785
+
1786
+ topic('sync:') {
1787
+
1788
+ topic 'sync:both' do
1789
+ spec "download and upload commits" do
1790
+ ## TODO
1791
+ system! "git remote add origin git@github.com:u1/r1.git"
1792
+ at_end { system! "git remote remove origin" }
1793
+ dryrun_mode do
1794
+ _, sout = main "sync:both", "-U"
1795
+ ok {sout} == <<~"END"
1796
+ [gi]$ git pull --prune
1797
+ [gi]$ git push -u origin main
1798
+ END
1799
+ end
1800
+ end
1801
+ end
1802
+
1803
+ topic 'sync:pull' do
1804
+ spec "download commits from remote and apply them to local" do
1805
+ ## TODO
1806
+ dryrun_mode do
1807
+ _, sout = main "sync:pull"
1808
+ ok {sout} == "[gi]$ git pull --prune\n"
1809
+ end
1810
+ end
1811
+ end
1812
+
1813
+ topic 'sync:push' do
1814
+ spec "upload commits" do
1815
+ ## TODO
1816
+ dryrun_mode do
1817
+ _, sout = main "sync:push", stdin: "\n"
1818
+ ok {sout} == <<~"END"
1819
+ Enter the remote repo name (default: \e[1morigin\e[0m) : [gi]$ git push -u origin main
1820
+ END
1821
+ end
1822
+ end
1823
+ end
1824
+
1825
+ }
1826
+
1827
+
1828
+ topic('tag:') {
1829
+
1830
+ before do
1831
+ system! "git tag --list | xargs git tag --delete >/dev/null"
1832
+ end
1833
+
1834
+ topic 'tag:handle' do
1835
+ spec "list/show/create/delete tags" do
1836
+ tag = "tg3454"
1837
+ ## create
1838
+ output, sout = main "tag", tag, "HEAD"
1839
+ ok {sout} == "[gi]$ git tag #{tag} HEAD\n"
1840
+ ok {`git tag -l`}.include?(tag)
1841
+ ## list
1842
+ output, sout = main "tag"
1843
+ ok {sout} == "[gi]$ git tag -l\n"
1844
+ ok {output} == <<~'END'
1845
+ tg3454
1846
+ END
1847
+ ## show
1848
+ output, sout = main "tag", tag
1849
+ ok {sout} == "[gi]$ git rev-parse #{tag}\n"
1850
+ ok {output} =~ /\A\h{40}\n\z/
1851
+ ## delete
1852
+ output, sout = main "tag", tag, ""
1853
+ ok {sout} == "[gi]$ git tag --delete #{tag}\n"
1854
+ ok {output} =~ /\ADeleted tag '#{tag}'/
1855
+ ok {`git tag -l`}.NOT.include?(tag)
1856
+ end
1857
+ spec "supports '-r, --remote' option." do
1858
+ tag = "tg6023"
1859
+ ## create
1860
+ output, sout, serr, status = main! "tag", '-r', tag, "HEAD", tty: true
1861
+ ok {status} != 0
1862
+ ok {serr} == <<~"END"
1863
+ \e[31m[ERROR]\e[0m Option '-r' or '--remote' is not available for creating tag.
1864
+ END
1865
+ ok {sout} == ""
1866
+ ## list
1867
+ dryrun_mode do
1868
+ output, sout = main "tag", '-r'
1869
+ ok {sout} == "[gi]$ git ls-remote --tags\n"
1870
+ ok {output} == ""
1871
+ end
1872
+ ## show
1873
+ output, sout, serr, status = main! "tag", '-r', tag, tty: true
1874
+ ok {status} != 0
1875
+ ok {serr} == <<~"END"
1876
+ \e[31m[ERROR]\e[0m Option '-r' or '--remote' is not available for showing tag.
1877
+ END
1878
+ ok {sout} == ""
1879
+ ## delete
1880
+ dryrun_mode do
1881
+ output, sout = main "tag", '-r', tag, ""
1882
+ ok {sout} == "[gi]$ git push origin :refs/tags/#{tag}\n"
1883
+ ok {output} == ""
1884
+ end
1885
+ end
1886
+ end
1887
+
1888
+ topic 'tag:create' do
1889
+ spec "create a new tag" do
1890
+ tag = "tg6740"
1891
+ output, sout = main "tag:create", tag
1892
+ ok {sout} == "[gi]$ git tag #{tag}\n"
1893
+ ok {output} == ""
1894
+ ok {`git tag --list`} == <<~"END"
1895
+ #{tag}
1896
+ END
1897
+ end
1898
+ end
1899
+
1900
+ topic 'tag:delete' do
1901
+ spec "delete a tag" do
1902
+ tag = "tg6988"
1903
+ system! "git tag #{tag}"
1904
+ ok {`git tag --list`}.include?(tag)
1905
+ output, sout = main "tag:delete", tag
1906
+ ok {sout} == "[gi]$ git tag -d tg6988\n"
1907
+ ok {output} =~ /\ADeleted tag '#{tag}' \(was \h{7}\)\n\z/
1908
+ ok {`git tag --list`}.NOT.include?(tag)
1909
+ end
1910
+ end
1911
+
1912
+ topic 'tag:list' do
1913
+ spec "list tags" do
1914
+ tag1 = "tg3352xx"
1915
+ tag2 = "tg3352yy"
1916
+ system! "git tag #{tag1}"
1917
+ system! "git tag #{tag2}"
1918
+ output, sout = main "tag:list"
1919
+ ok {sout} == "[gi]$ git tag -l\n"
1920
+ ok {output} == <<~"END"
1921
+ #{tag1}
1922
+ #{tag2}
1923
+ END
1924
+ end
1925
+ end
1926
+
1927
+ topic 'tag:download' do
1928
+ spec "download tags" do
1929
+ ## TODO
1930
+ dryrun_mode do
1931
+ _, sout = main "tag:download"
1932
+ ok {sout} == "[gi]$ git fetch --tags --prune-tags\n"
1933
+ end
1934
+ end
1935
+ end
1936
+
1937
+ topic 'tag:upload' do
1938
+ spec "upload tags" do
1939
+ ## TODO
1940
+ dryrun_mode do
1941
+ _, sout = main "tag:upload"
1942
+ ok {sout} == "[gi]$ git push --tags\n"
1943
+ end
1944
+ end
1945
+ end
1946
+
1947
+ }
1948
+
1949
+
1950
+ end
1951
+
1952
+
1953
+ end