git-improved 0.1.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.
@@ -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