squared 0.2.10 → 0.3.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.
@@ -72,23 +72,111 @@ module Squared
72
72
 
73
73
  module Project
74
74
  class Git < Base
75
- FOR_FETCH = %w[atomic multiple negotiate-only prefetch progress prune-tags refetch].freeze
76
- NO_FETCH = %w[all ipv4 ipv6 recurse-submodules show-forced-updates tags].freeze
77
- FNO_FETCH = %w[auto-gc auto-maintenance write-commit-graph write-fetch-head].freeze
78
- OPT_FETCH = (FOR_FETCH + NO_FETCH + FNO_FETCH +
79
- %w[append dry-run force keep prune quiet set-upstream unshallow update-shallow verbose
80
- deepen=i depth=i jobs=i negotiation-tip=s refmap=s recurse-submodules=s server-option=s
81
- shallow-exclude=s shallow-since=d upload-pack=s]).freeze
82
- NO_PULL = %w[allow-unrelated-histories autostash commit edit ff signoff squash stat verify verify-signatures
83
- gpg-sign=? log=? rebase=?].freeze
84
- OPT_PULL = (NO_PULL + %w[ff-only signoff=s strategy=s strategy-option=s]).freeze
85
- OPT_REBASE = %w[continue skip abort quit].freeze
86
- VAL_REBASE = %w[true false merges interactive].freeze
87
- NO_BRANCH = %w[abbrev=i color=? column=? track=?].freeze
88
- OPT_BRANCH = (NO_BRANCH + %w[all create-reflog ignore-case quiet remotes verbose
89
- contains=s format=s merged=s no-contains=s no-merged=s points-at=s sort=s]).freeze
90
- private_constant :FOR_FETCH, :NO_FETCH, :FNO_FETCH, :OPT_FETCH, :NO_PULL, :OPT_PULL, :OPT_REBASE, :VAL_REBASE,
91
- :NO_BRANCH, :OPT_BRANCH
75
+ OPT_GIT = {
76
+ branch: %w[a|all create-reflog i|ignore-case q|quiet r|remotes v|verbose abbrev=i color=b column=b
77
+ contains=e format=q merged=e no-contains=e no-merged=e points-at=e u|set-upstream-to=e sort=q
78
+ t|track=b].freeze,
79
+ checkout: %w[l d|detach f|force ignore-other-worktrees ignore-skip-worktree-bits m|merge p|patch
80
+ pathspec-file-nul q quiet orphan=e ours theirs conflict=b pathspec-from-file=p
81
+ t|track=b].freeze,
82
+ diff: {
83
+ base: %w[0 1|base 2|ours 3|theirs].freeze,
84
+ show: %w[s exit-code histogram].freeze
85
+ }.freeze,
86
+ fetch: {
87
+ base: %w[multiple progress P|prune-tags refetch stdin u|update-head-ok recurse-submodules=s
88
+ recurse-submodules-default=b].freeze,
89
+ pull: %w[4 6 n t a|append atomic dry-run f|force k|keep n|negotiate-only prefetch p|prune q|quiet
90
+ set-upstream unshallow update-shallow v|verbose deepen=i depth=i j|jobs=i negotiation-tip=q
91
+ refmap=q o|server-option=e shallow-exclude=e shallow-since=s upload-pack=e].freeze
92
+ }.freeze,
93
+ log: {
94
+ base: %w[all all-match alternate-refs author-date-order basic-regexp bisect boundary cherry cherry-mark
95
+ cherry-pick clear-decorations date-order dense do-walk exclude-first-parent-only E|extended-regexp
96
+ first-parent F|fixed-strings follow full-diff full-history ignore-missing invert-grep left-only
97
+ merge log-size no-max-parents no-min-parents not P|perl-regexp reflog i|regexp-ignore-case
98
+ remove-empty reverse right-only simplify-by-decoration simplify-merges single-worktree show-pulls
99
+ source sparse stdin topo-order g|walk-reflogs after=q ancestry-path=e? author=q before=q
100
+ branches=q? committer=q decorate=b decorate-refs=q decorate-refs-exclude=q exclude=q
101
+ exclude-hidden=b? glob=q grep=q grep-reflog=q L=q n|max-count=i max-parents=i min-parents=i
102
+ no-walk=b? remotes=q? since=q since-as-filter=q skip=i tags=q? until=q].freeze,
103
+ format: %w[t children combined-all-paths oneline left-right no-diff-merges parents relative-date
104
+ show-signature date=q diff-merges=b encoding=b expand-tabs=i format=q notes=q pretty=q?
105
+ show-linear-break=q?].freeze,
106
+ diff: %w[p R u z l=i G=q O=q S=q binary check compact-summary cumulative find-copies-harder full-index
107
+ W|function-context w|ignore-all-space ignore-blank-lines ignore-cr-at-eol ignore-space-at-eol
108
+ b|ignore-space-change D|irreversible-delete graph ita-invisible-in-index minimal name-only
109
+ name-status no-color-moved-ws no-prefix no-renames numstat patch-with-raw patch-with-stat patience
110
+ pickaxe-all pickaxe-regex raw shortstat summary a|text abbrev=i? anchored=q B|break-rewrites=e?
111
+ color=b color-moved=b color-moved-ws=b color-words=q? diff-algorithm=b diff-filter=e? X|dirstat=q?
112
+ dirstat-by-file=q? dst-prefix=q C|find-copies=i? find-object=e M|find-renames=i?
113
+ I|ignore-matching-lines=q ignore-submodules=b inter-hunk-context=i line-prefix=q output=p
114
+ output-indicator-context=q output-indicator-new=q output-indicator-old=q relative=p rotate-to=p
115
+ skip-to=p src-prefix=q stat=q? stat-width=i stat-name-width=i stat-count=i submodule=b? U|unified=i
116
+ word-diff=b? word-diff-regex=q ws-error-highligt=q].freeze
117
+ }.freeze,
118
+ ls_files: %w[z debug deduplicate directory eol error-unmatch exclude-standard full-name k|killed
119
+ no-empty-directory recurse-submodules sparse s|stage u|unmerged abbrev=i x|exclude=q
120
+ X|exclude-from=p exclude-per-directory=p format=q with-tree=q].freeze,
121
+ ls_remote: %w[exit-code get-url q|quiet o|server-option=e symref sort=q upload-pack=e].freeze,
122
+ pull: %w[e n allow-unrelated-histories ff-only S|gpg-sign=e log=i rebase=s s|strategy=b
123
+ X|strategy-option=e].freeze,
124
+ rebase: %w[n C=i allow-empty-message apply committer-date-is-author-date edit-todo f|force-rebase ignore-date
125
+ ignore-whitespace i|interactive keep-base m merge no-ff q|quiet quit r|rebase-merges=b?
126
+ reset-author-date root show-current-patch signoff v|verbose empty=b S|gpg-sign=b onto=e
127
+ s|strategy=b X|strategy-option=b whitespace=e].freeze,
128
+ reset: %w[N pathspec-file-nul q|quiet pathspec-from-file=p].freeze,
129
+ restore: %w[ignore-unmerged ignore-skip-worktree-bits m|merge ours p|patch pathspec-file-nul S|staged theirs
130
+ W|worktree conflict=b pathspec-from-file=p s|source=q].freeze,
131
+ rev_parse: {
132
+ output: %w[absolute-git-dir all flags git-common-dir git-dir is-bare-repository is-inside-git-dir
133
+ is-inside-work-tree is-shallow-repository local-env-vars no-flags no-revs not q|quiet sq
134
+ revs-only shared-index-path show-cdup show-prefix show-toplevel show-superproject-working-tree
135
+ sq-quote symbolic symbolic-full-name verify abbrev-ref=b? after=q before=q default=e
136
+ disambiguate=b exclude=q exclude-hidden=b glob=q git-path=p path-format=b? prefix=q branches=q?
137
+ remotes=q? resolve-git-dir=p short=i? show-object-format=b? since=q tags=q? until=q].freeze,
138
+ parseopt: %w[keep-dashdash stop-at-non-option stuck-long].freeze
139
+ }.freeze,
140
+ show: %w[t combined-all-paths no-diff-merges remerge-diff show-signature diff-merges=b encoding=b
141
+ expand-tabs=i notes=q show-notes=q?].freeze,
142
+ stash: {
143
+ common: %w[q|quiet].freeze,
144
+ push: %w[a|all u|include-untracked k|keep-index no-keep-index p|patch S|staged m|message=q
145
+ pathspec-from-file=p].freeze,
146
+ pop: %w[index].freeze,
147
+ apply: %w[index].freeze
148
+ }.freeze,
149
+ tag: %w[create-reflog column=b contains=e? format=q merged=e? n=i no-contains=e? no-merged=e? points-at=q
150
+ sort=q].freeze,
151
+ no: {
152
+ fetch: {
153
+ base: %w[auto-gc auto-maintenance write-commit-graph write-fetch-head].freeze,
154
+ pull: %w[all ipv4 ipv6 recurse-submodules show-forced-updates tags].freeze
155
+ },
156
+ log: {
157
+ base: %w[decorate mailmap merges use-mailmap].freeze,
158
+ show: %w[abbrev-commit expand-tabs notes].freeze,
159
+ diff: %w[color color-moved ext-diff indent-heuristic patch relative rename-empty textconv].freeze
160
+ }.freeze,
161
+ pull: %w[autostash commit edit ff log signoff squash stat verify verify-signatures gpg-sign rebase].freeze,
162
+ tag: %w[column].freeze,
163
+ branch: %w[color-moved column color track].freeze,
164
+ checkout: %w[overwrite-ignore guess overlay progress recurse-submodules track].freeze,
165
+ rebase: %w[autosquash autostash fork-point gpg-sign keep-empty reapply-cherry-picks reschedule-failed-exec
166
+ rerere-autoupdate stat update-refs verify].freeze,
167
+ reset: %w[refresh].freeze,
168
+ restore: %w[overlay progress recurse-submodules].freeze,
169
+ show: %w[standard-notes].freeze
170
+ }.freeze
171
+ }
172
+ VAL_GIT = {
173
+ rebase: {
174
+ send: %w[continue skip abort quit].freeze,
175
+ value: %w[true false merges interactive].freeze
176
+ }.freeze,
177
+ reset: %w[soft mixed hard merge keep recurse-submodules no-recurse-submodules].freeze
178
+ }
179
+ private_constant :OPT_GIT, :VAL_GIT
92
180
 
93
181
  class << self
94
182
  include Rake::DSL
@@ -134,21 +222,22 @@ module Squared
134
222
  end
135
223
 
136
224
  @@tasks[ref] = {
137
- 'checkout' => %i[branch track detach force merge].freeze,
138
- 'commit' => %i[add amend amend-orig all no-all].freeze,
139
- 'diff' => %i[head cached branch files between contain].freeze,
140
- 'pull' => %i[origin remote].freeze,
141
- 'fetch' => %i[origin remote].freeze,
142
- 'stash' => %i[push pop apply list clear].freeze,
143
- 'rebase' => %i[onto root send].freeze,
144
225
  'branch' => %i[create set delete move copy list edit current].freeze,
145
- 'refs' => %i[heads tags].freeze,
146
- 'files' => %i[cached modified deleted others].freeze,
147
- 'reset' => %i[head patch mode].freeze,
226
+ 'checkout' => %i[commit branch track detach path].freeze,
227
+ 'commit' => %i[add all amend amend-orig].freeze,
228
+ 'diff' => %i[head cached branch files view between contain].freeze,
229
+ 'fetch' => %i[origin remote].freeze,
230
+ 'files' => %i[cached modified deleted others ignored].freeze,
231
+ 'log' => %i[view between contain].freeze,
232
+ 'pull' => %i[origin remote].freeze,
233
+ 'rebase' => %i[branch onto send].freeze,
234
+ 'refs' => %i[heads tags remote].freeze,
235
+ 'reset' => %i[commit index patch mode].freeze,
148
236
  'restore' => %i[source worktree staged overlay].freeze,
149
- 'rev' => %i[commit branch].freeze,
237
+ 'rev' => %i[commit branch output parseopt].freeze,
150
238
  'show' => %i[format oneline].freeze,
151
- 'tag' => %i[add delete list merged].freeze
239
+ 'stash' => %i[push pop apply drop list].freeze,
240
+ 'tag' => %i[add delete list].freeze
152
241
  }.freeze
153
242
 
154
243
  def initialize(*, **)
@@ -173,93 +262,96 @@ module Squared
173
262
  case action
174
263
  when 'pull', 'fetch'
175
264
  if flag == :remote
176
- if @@task_desc
177
- format_desc(action, flag, ['refspec=s'] + (action == 'pull' ? OPT_PULL : OPT_FETCH),
178
- before: 'remote')
179
- end
265
+ format_desc(action, flag, 'remote,opts*')
180
266
  task flag, [:remote] do |_, args|
181
267
  remote = param_guard(action, flag, args: args, key: :remote)
182
- __send__(action, flag, remote: remote, opts: args.extras)
268
+ __send__(action, flag, args.extras, remote: remote)
183
269
  end
184
270
  else
185
- format_desc(action, flag, action == 'pull' ? OPT_PULL : OPT_FETCH)
271
+ format_desc action, flag, 'opts*'
186
272
  task flag do |_, args|
187
- __send__(action, flag, opts: args.to_a)
273
+ __send__ action, flag, args.to_a
188
274
  end
189
275
  end
190
- when 'commit', 'restore'
276
+ when 'commit'
191
277
  case flag
192
278
  when :all
193
279
  format_desc action, flag, 'message?'
194
280
  task flag, [:message] do |_, args|
195
281
  commit(flag, message: args.fetch(:message, nil))
196
282
  end
197
- when :source
198
- format_desc action, flag, 'tree,pathspec*'
283
+ else
284
+ format_desc action, flag, 'pathspec+'
285
+ task flag do |_, args|
286
+ refs = param_guard(action, flag, args: args.to_a)
287
+ commit(flag, refs: refs)
288
+ end
289
+ end
290
+ when 'restore'
291
+ if flag == :source
292
+ format_desc action, flag, 'tree,opts*,pathspec*'
199
293
  task flag, [:tree] do |_, args|
200
294
  tree = param_guard(action, flag, args: args, key: :tree)
201
295
  restore(flag, args.extras, tree: tree)
202
296
  end
203
297
  else
204
- format_desc action, flag, 'pathspec+'
298
+ format_desc action, flag, 'opts*,pathspec+'
205
299
  task flag do |_, args|
206
- files = param_guard(action, flag, args: args.to_a)
207
- __send__ action, flag, files
300
+ restore flag, args.to_a
208
301
  end
209
302
  end
210
303
  when 'tag'
211
304
  case flag
212
305
  when :list
213
- format_desc action, flag, 'pattern*'
306
+ format_desc action, flag, 'opts*,pattern*'
214
307
  task flag do |_, args|
215
308
  tag flag, args.to_a
216
309
  end
217
- when :merged
218
- format_desc action, flag, 'commit,pattern*'
219
- task flag, [:commit] do |_, args|
220
- commit = param_guard(action, flag, args: args, key: :commit)
221
- tag(flag, args.extras, commit: commit)
222
- end
223
310
  when :delete
224
311
  format_desc action, flag, 'name+'
225
312
  task flag do |_, args|
226
- name = param_guard(action, flag, args: args.to_a)
227
- tag flag, name
313
+ refs = param_guard(action, flag, args: args.to_a)
314
+ tag(flag, refs: refs)
228
315
  end
229
316
  when :add
230
317
  format_desc action, flag, 'name,message?,commit?'
231
318
  task flag, [:name, :message, :commit] do |_, args|
232
319
  name = param_guard(action, flag, args: args, key: :name)
233
- tag(flag, [name], message: args.message, commit: args.commit)
320
+ tag(flag, refs: [name], message: args.message, commit: args.commit)
234
321
  end
235
322
  end
236
323
  when 'stash'
237
- if flag == :push
238
- format_desc action, flag, 'pathspec*'
239
- task flag do |_, args|
240
- stash flag, args.to_a
241
- end
324
+ if flag == :list
325
+ format_desc action, flag
242
326
  else
243
- format_desc action, flag, 'commit?'
244
- task flag, [:commit] do |_, args|
245
- stash(flag, commit: args.commit)
246
- end
327
+ format_desc(action, flag, '*opts', after: flag == :push ? 'pathspec*' : 'commit?')
247
328
  end
248
- when 'diff'
329
+ task flag do |_, args|
330
+ stash flag, args.to_a
331
+ end
332
+ when 'log', 'diff'
249
333
  case flag
250
- when :head
251
- format_desc action, flag, 'index?=0,pathspec*'
252
- task flag do |_, args|
253
- files = args.to_a
254
- diff(flag, files, index: /\A\d+\z/.match?(files[0]) && !option('index') ? files.shift.to_i : 0)
334
+ when :view, :between, :contain
335
+ if flag == :view && action == 'log'
336
+ format_desc action, flag, '(^)commit*,pathspec*,opts*'
337
+ task flag do |_, args|
338
+ logx flag, args.to_a
339
+ end
340
+ else
341
+ format_desc action, flag, 'commit1,commit2,pathspec*,opts*'
342
+ task flag, [:commit1, :commit2] do |_, args|
343
+ commit1 = param_guard(action, flag, args: args, key: :commit1)
344
+ commit2 = param_guard(action, flag, args: args, key: :commit2)
345
+ __send__(action == 'log' ? :logx : :diff, flag, args.extras, range: [commit1, commit2])
346
+ end
255
347
  end
256
- when :cached
257
- format_desc action, flag, 'pathspec*'
348
+ when :head, :cached
349
+ format_desc action, flag, 'opts*,pathspec*'
258
350
  task flag do |_, args|
259
351
  diff flag, args.to_a
260
352
  end
261
353
  when :branch
262
- format_desc action, flag, 'name,pathspec*'
354
+ format_desc action, flag, 'name,opts*,pathspec*'
263
355
  task flag, [:name] do |_, args|
264
356
  branch = param_guard(action, flag, args: args, key: :name)
265
357
  diff(flag, args.extras, branch: branch)
@@ -269,14 +361,7 @@ module Squared
269
361
  task flag, [:path1, :path2] do |_, args|
270
362
  path1 = param_guard(action, flag, args: args, key: :path1)
271
363
  path2 = param_guard(action, flag, args: args, key: :path2)
272
- diff flag, [path1, path2]
273
- end
274
- else
275
- format_desc action, flag, 'commit1,commit2,pathspec*'
276
- task flag, [:commit1, :commit2] do |_, args|
277
- commit1 = param_guard(action, flag, args: args, key: :commit1)
278
- commit2 = param_guard(action, flag, args: args, key: :commit2)
279
- diff(flag, args.extras, range: [commit1, commit2])
364
+ diff(flag, refs: [path1, path2])
280
365
  end
281
366
  end
282
367
  when 'checkout'
@@ -310,13 +395,19 @@ module Squared
310
395
  origin = param_guard(action, flag, args: args, key: :origin)
311
396
  checkout(flag, branch: args.name, origin: origin)
312
397
  end
398
+ when :commit
399
+ format_desc action, flag, 'branch/commit,opts*'
400
+ task flag, [:commit] do |_, args|
401
+ commit = param_guard(action, flag, args: args, key: :commit)
402
+ checkout(flag, commit: commit)
403
+ end
313
404
  when :detach
314
405
  format_desc action, flag, 'branch/commit?'
315
406
  task flag, [:commit] do |_, args|
316
407
  checkout(flag, commit: args.commit)
317
408
  end
318
- else
319
- format_desc action, flag, 'pathspec*'
409
+ when :path
410
+ format_desc action, flag, 'opts*,pathspec*'
320
411
  task flag do |_, args|
321
412
  checkout flag, args.to_a
322
413
  end
@@ -326,11 +417,11 @@ module Squared
326
417
  when :create
327
418
  format_desc action, flag, 'name,ref?=HEAD'
328
419
  task flag, [:name, :ref] do |_, args|
329
- name = param_guard(action, flag, args: args, key: :name)
330
- branch(flag, target: name, ref: args.ref)
420
+ target = param_guard(action, flag, args: args, key: :name)
421
+ branch(flag, target: target, ref: args.ref)
331
422
  end
332
423
  when :set
333
- format_desc(action, flag, '(!)upstream,name?')
424
+ format_desc(action, flag, '(^)upstream,name?')
334
425
  task flag, [:upstream, :name] do |_, args|
335
426
  upstream = param_guard(action, flag, args: args, key: :upstream)
336
427
  branch(flag, target: args.name, ref: upstream)
@@ -338,8 +429,8 @@ module Squared
338
429
  when :delete
339
430
  format_desc action, flag, '(^~)name+'
340
431
  task flag, [:name] do |_, args|
341
- name = param_guard(action, flag, args: args.to_a)
342
- branch flag, name
432
+ refs = param_guard(action, flag, args: args.to_a)
433
+ branch(flag, refs: refs)
343
434
  end
344
435
  when :edit
345
436
  format_desc action, flag, 'name?'
@@ -347,9 +438,9 @@ module Squared
347
438
  branch(flag, target: args.name)
348
439
  end
349
440
  when :list
350
- format_desc(action, flag, OPT_BRANCH, before: 'pattern*')
441
+ format_desc action, flag, 'opts*,pattern*'
351
442
  task flag do |_, args|
352
- branch(flag, opts: args.to_a)
443
+ branch flag, args.to_a
353
444
  end
354
445
  when :current
355
446
  format_desc action, flag
@@ -357,74 +448,109 @@ module Squared
357
448
  branch flag
358
449
  end
359
450
  else
360
- format_desc action, flag, 'newbranch,oldbranch?'
361
- task flag, [:newbranch, :oldbranch] do |_, args|
362
- newbranch = param_guard(action, flag, args: args, key: :newbranch)
363
- branch flag, [args.oldbranch, newbranch]
451
+ format_desc action, flag, 'branch,oldbranch?'
452
+ task flag, [:branch, :oldbranch] do |_, args|
453
+ branch = param_guard(action, flag, args: args, key: :branch)
454
+ branch(flag, refs: [args.oldbranch, branch])
364
455
  end
365
456
  end
366
457
  when 'reset'
367
458
  case flag
368
- when :mode
369
- if @@task_desc
370
- format_desc(action, flag, %w[soft mixed hard merge keep {no-}submodules], after: 'ref?=HEAD',
371
- arg: false)
459
+ when :commit
460
+ format_desc action, flag, 'branch/commit,opts*'
461
+ task flag, [:commit] do |_, args|
462
+ commit = param_guard(action, flag, args: args, key: :commit)
463
+ reset(flag, args.extras, commit: commit)
464
+ end
465
+ when :index
466
+ format_desc action, flag, 'opts*,pathspec*'
467
+ task flag do |_, args|
468
+ reset flag, args.to_a
372
469
  end
470
+ when :mode
471
+ format_desc action, flag, 'mode,ref?=HEAD'
373
472
  task flag, [:mode, :ref] do |_, args|
374
473
  mode = param_guard(action, flag, args: args, key: :mode)
375
474
  reset(flag, mode: mode, ref: args.ref)
376
475
  end
377
- else
378
- format_desc action, flag, 'ref,pathspec+'
476
+ when :patch
477
+ format_desc action, flag, 'ref,pathspec*'
379
478
  task flag, [:ref] do |_, args|
380
- files = param_guard(action, flag, args: args.extras)
381
- reset(flag, files, ref: args.ref)
479
+ ref = param_guard(action, flag, args: args, key: :ref)
480
+ reset(flag, refs: args.extras, ref: ref)
382
481
  end
383
482
  end
384
483
  when 'show'
385
484
  case flag
386
485
  when :oneline
387
- format_desc action, flag, 'object*'
486
+ format_desc action, flag, 'opts*,object*'
388
487
  task flag do |_, args|
389
- show(args.to_a, format: 'oneline', opts: { 'abbrev-commit': true })
488
+ show 'oneline', args.to_a.push('abbrev-commit')
390
489
  end
391
490
  when :format
392
- format_desc action, flag, 'format?,object*'
491
+ format_desc action, flag, 'format?,opts*,object*'
393
492
  task flag, [:format] do |_, args|
394
- show(args.extras, format: args.format)
493
+ show args.format, args.extras
395
494
  end
396
495
  end
397
496
  when 'rebase'
398
497
  case flag
498
+ when :branch
499
+ format_desc action, flag, 'opts*,upstream?,branch?'
500
+ task flag do |_, args|
501
+ args = param_guard(action, flag, args: args.to_a)
502
+ rebase flag, args
503
+ end
399
504
  when :onto
400
- format_desc action, flag, 'commit,upstream,branch?=HEAD'
505
+ format_desc action, flag, 'branch/commit,upstream,branch?=HEAD'
401
506
  task flag, [:commit, :upstream, :branch] do |_, args|
402
507
  commit = param_guard(action, flag, args: args, key: :commit)
403
508
  upstream = param_guard(action, flag, args: args, key: :upstream)
404
509
  rebase(flag, commit: commit, upstream: upstream, branch: args.branch)
405
510
  end
406
- when :root
407
- format_desc action, flag, 'branch,onto?'
408
- task flag, [:branch, :onto] do |_, args|
409
- branch = param_guard(action, flag, args: args, key: :branch)
410
- rebase(flag, commit: args.onto, branch: branch)
411
- end
412
511
  when :send
413
- format_desc(action, flag, OPT_REBASE, arg: nil)
512
+ format_desc(action, flag, VAL_GIT[:rebase][:send], arg: nil)
414
513
  task flag, [:command] do |_, args|
415
514
  command = param_guard(action, flag, args: args, key: :command)
416
515
  rebase(flag, command: command)
417
516
  end
418
517
  end
419
518
  when 'rev'
420
- format_desc(action, flag, "ref?=HEAD#{flag == :commit ? ',size?' : ''}")
421
- task flag, [:ref, :size] do |_, args|
422
- rev_parse(flag, ref: args.ref, size: args.size)
519
+ case flag
520
+ when :commit
521
+ format_desc action, flag, 'ref?=HEAD,size?'
522
+ task flag, [:ref, :size] do |_, args|
523
+ ref = args.ref
524
+ size = args.size
525
+ if !size && ref.to_i > 0
526
+ size = ref
527
+ ref = nil
528
+ end
529
+ rev_parse(flag, ref: ref, size: size)
530
+ end
531
+ when :branch
532
+ format_desc action, flag, 'ref?=HEAD'
533
+ task flag, [:ref] do |_, args|
534
+ rev_parse(flag, ref: args.ref)
535
+ end
536
+ else
537
+ format_desc action, flag, 'opts*,args*'
538
+ task flag do |_, args|
539
+ rev_parse flag, args.to_a
540
+ end
423
541
  end
424
542
  when 'refs', 'files'
425
- format_desc action, flag, 'grep?=pattern'
426
- task flag, [:grep] do |_, args|
427
- __send__(action == 'refs' ? :ls_remote : :ls_files, flag, grep: args.fetch(:grep, nil))
543
+ if flag == :remote
544
+ format_desc action, flag, 'remote,opts*,pattern*'
545
+ task flag, [:remote] do |_, args|
546
+ remote = param_guard(action, flag, args: args, key: :remote)
547
+ ls_remote(flag, args.to_a.drop(1), remote: remote)
548
+ end
549
+ else
550
+ format_desc action, flag, 'opts*,pattern*'
551
+ task flag do |_, args|
552
+ __send__(action == 'refs' ? :ls_remote : :ls_files, flag, args.to_a)
553
+ end
428
554
  end
429
555
  end
430
556
  end
@@ -438,21 +564,18 @@ module Squared
438
564
  super
439
565
  end
440
566
 
441
- def pull(flag = nil, sync: invoked_sync?('pull', flag), remote: nil, opts: [])
567
+ def pull(flag = nil, opts = [], sync: invoked_sync?('pull', flag), remote: nil)
442
568
  cmd = git_session 'pull'
443
- if flag == :rebase
444
- cmd << '--rebase'
445
- cmd << '--autostash' if option('autostash')
446
- elsif (val = option('rebase', ignore: false))
569
+ if (val = option('rebase', ignore: false))
447
570
  cmd << case val
448
571
  when '0'
449
572
  '--no-rebase'
450
573
  else
451
- VAL_REBASE.include?(val) ? basic_option('rebase', val) : '--rebase'
574
+ VAL_GIT[:rebase][:value].include?(val) ? basic_option('rebase', val) : '--rebase'
452
575
  end
453
576
  end
454
- append_pull(opts, OPT_PULL + OPT_FETCH - (FOR_FETCH + FNO_FETCH), NO_PULL + NO_FETCH, remote: remote,
455
- flag: flag)
577
+ append_pull(opts, OPT_GIT[:pull] + OPT_GIT[:fetch][:pull],
578
+ no: OPT_GIT[:no][:pull] + OPT_GIT[:no][:fetch][:pull], remote: remote, flag: flag)
456
579
  source(sync: sync, sub: if verbose
457
580
  [
458
581
  { pat: /^(.+)(\|\s+\d+\s+)([^-]*)(-+)(.*)$/, styles: :red, index: 4 },
@@ -461,39 +584,44 @@ module Squared
461
584
  end, **threadargs)
462
585
  end
463
586
 
464
- def rebase(flag = nil, sync: invoked_sync?('rebase', flag), command: nil, commit: nil, upstream: nil,
465
- branch: nil)
587
+ def rebase(flag = nil, opts = [], sync: invoked_sync?('rebase', flag), commit: nil, upstream: nil, branch: nil,
588
+ command: nil)
466
589
  return pull(:rebase, sync: sync) unless flag
467
590
 
468
591
  cmd = git_session 'rebase'
469
- cmd << '--interactive' unless flag == :send || !option('interactive', 'i')
470
592
  case flag
593
+ when :branch
594
+ branch = option_sanitize(opts, OPT_GIT[:rebase], no: OPT_GIT[:no][:rebase]).first
595
+ case branch.size
596
+ when 0
597
+ append_head
598
+ when 1, 2
599
+ append_value(branch, delim: true)
600
+ else
601
+ append_value([branch.pop, branch.pop].reverse, delim: true)
602
+ option_clear branch
603
+ end
471
604
  when :onto
472
605
  return unless upstream
473
606
 
474
- cmd << shell_option('onto', commit)
607
+ cmd << '--interactive' if option('interactive', 'i')
608
+ cmd << shell_option('onto', commit) if commit
475
609
  cmd << shell_escape(upstream)
476
610
  append_head branch
477
- when :root
478
- return unless branch
479
-
480
- cmd << shell_option('onto', commit) if commit
481
- cmd << '--root' << shell_escape(branch)
482
- when :send
483
- return unless OPT_REBASE.include?(command)
611
+ else
612
+ return unless VAL_GIT[:rebase][:send].include?(command)
484
613
 
485
614
  cmd << "--#{command}"
486
- else
487
- return
488
615
  end
489
616
  source
490
617
  end
491
618
 
492
- def fetch(flag = nil, sync: invoked_sync?('fetch', flag), remote: nil, opts: [])
619
+ def fetch(flag = nil, opts = [], sync: invoked_sync?('fetch', flag), remote: nil)
493
620
  cmd = git_session 'fetch'
494
621
  cmd << '--all' if !remote && !opts.include?('multiple') && option('all')
495
622
  cmd << '--verbose' if verbose && !opts.include?('quiet')
496
- append_pull(opts, OPT_FETCH, NO_FETCH + FNO_FETCH, remote: remote, flag: flag)
623
+ append_pull(opts, collect_hash(OPT_GIT[:fetch]), no: collect_hash(OPT_GIT[:no][:fetch]),
624
+ remote: remote, flag: flag)
497
625
  source(sync: sync, **threadargs)
498
626
  end
499
627
 
@@ -514,36 +642,39 @@ module Squared
514
642
  opts[:local] = val != '0' if (val = option('local', strict: true))
515
643
  opts.delete(:'recurse-submodules') || opts.delete(:'no-recurse-submodules') if append_submodules(:clone)
516
644
  append_hash opts
517
- if cmd.include?('--quiet') || cmd.include?('-q')
518
- quiet = true
519
- elsif verbose
520
- quiet = false
521
- else
522
- cmd << '--quiet'
523
- quiet = true
524
- end
525
- append_value([data[0], path], delim: true, escape: false)
526
- source(banner: sync && !quiet, multiple: !sync || quiet)
645
+ cmd << '--quiet' unless verbose
646
+ append_value(data[0], path, delim: true)
647
+ source(banner: sync && !quiet?, multiple: !sync || quiet?)
527
648
  end
528
649
 
529
- def stash(flag = nil, files = [], sync: invoked_sync?('stash', flag), commit: nil)
530
- cmd = git_session 'stash', flag || 'push'
531
- case flag
532
- when :apply, :pop
533
- cmd << '--index' if option('index')
534
- cmd << commit
650
+ def stash(flag = nil, opts = [], sync: invoked_sync?('stash', flag))
651
+ if flag
652
+ cmd = git_session 'stash', flag
653
+ list = OPT_GIT[:stash][:common] + OPT_GIT[:stash].fetch(flag, [])
654
+ refs = option_sanitize(opts, list).first
655
+ case flag
656
+ when :push
657
+ append_pathspec refs
658
+ when :pop, :apply, :drop
659
+ cmd << shell_quote(refs.pop)
660
+ option_clear refs
661
+ when :list
662
+ out, banner, from = source(io: true)
663
+ print_item banner
664
+ ret = write_lines(out)
665
+ list_result(ret, 'objects', from: from)
666
+ return
667
+ end
535
668
  else
536
- append_option %w[all staged include-untracked].freeze
669
+ git_session 'stash', 'push'
670
+ append_option(%w[all keep-index include-untracked staged].freeze, no: true, ignore: false)
537
671
  append_message option('message', 'm', ignore: false)
538
- append_pathspec files
539
672
  end
540
- source(sync: sync, **threadargs)
673
+ source(banner: !quiet?, sync: sync, **threadargs)
541
674
  end
542
675
 
543
676
  def status(*, sync: invoked_sync?('status'), **)
544
- cmd = git_session 'status'
545
- cmd << (option('long') ? '--long' : '--short')
546
- cmd << '--branch' if option('branch')
677
+ cmd = git_session 'status', option('long') ? '--long' : '--short'
547
678
  if (val = option('ignore-submodules', ignore: false))
548
679
  cmd << basic_option('ignore-submodules', case val
549
680
  when '0', 'none'
@@ -564,8 +695,8 @@ module Squared
564
695
  end
565
696
  ret = write_lines(out, banner: banner, sub: if verbose
566
697
  [
567
- { pat: /^(.)([A-Z?!])(.+)$/, styles: :red, index: 2 },
568
- { pat: /^([A-Z?!])(.+)$/, styles: :green },
698
+ { pat: /^(.)([A-Z])(.+)$/, styles: :red, index: 2 },
699
+ { pat: /^([A-Z])(.+)$/, styles: :green },
569
700
  { pat: /^(\?\?)(.+)$/, styles: :red },
570
701
  { pat: /^(## )(.+)(\.{3})(.+)$/,
571
702
  styles: [nil, :green, nil, :red], index: -1 }
@@ -574,34 +705,41 @@ module Squared
574
705
  list_result(ret, 'files', from: from, action: 'modified')
575
706
  end
576
707
 
577
- def reset(flag, files = nil, mode: nil, ref: nil)
708
+ def reset(flag, opts = [], refs: nil, ref: nil, mode: nil, commit: nil)
578
709
  cmd = git_session 'reset'
579
710
  case flag
711
+ when :commit, :index
712
+ out = option_sanitize(opts, OPT_GIT[:reset] + VAL_GIT[:reset], no: OPT_GIT[:no][:reset]).first
713
+ if flag == :commit
714
+ append_value(commit, delim: true)
715
+ option_clear out
716
+ ref = false
717
+ else
718
+ (refs ||= []).concat(out)
719
+ end
580
720
  when :mode
581
- case mode
582
- when 'mixed'
583
- cmd << '--mixed'
721
+ return unless VAL_GIT[:reset].include?(mode)
722
+
723
+ cmd << "--#{mode}"
724
+ if mode == 'mixed'
584
725
  cmd << '-N' if option('n')
585
726
  cmd << '--no-refresh' if option('refresh', equals: '0')
586
- when 'soft', 'hard', 'merge', 'keep'
587
- cmd << "--#{mode}"
588
- when 'submodules'
589
- cmd << '--recurse-submodules'
590
- when 'no-submodules'
591
- cmd << '--no-recurse-submodules'
592
- else
593
- return
594
727
  end
595
728
  when :patch
596
729
  cmd << '--patch'
730
+ else
731
+ return
732
+ end
733
+ unless ref == false
734
+ append_commit ref
735
+ append_pathspec refs if refs
597
736
  end
598
- append_commit ref
599
- append_pathspec files if files
600
737
  source
601
738
  end
602
739
 
603
- def checkout(flag, files = [], branch: nil, origin: nil, create: nil, commit: nil, detach: nil)
740
+ def checkout(flag, opts = [], branch: nil, origin: nil, create: nil, commit: nil, detach: nil)
604
741
  cmd = git_session 'checkout'
742
+ append_option 'force', 'merge'
605
743
  case flag
606
744
  when :branch
607
745
  cmd << '--detach' if detach == 'd' || option('detach')
@@ -624,92 +762,122 @@ module Squared
624
762
  end
625
763
  cmd << '--track' << origin
626
764
  when :detach
627
- cmd << "--#{flag}" << commit
765
+ cmd << '--detach' << commit
628
766
  else
629
- cmd << "--#{flag}"
630
- append_first %w[ours theirs]
631
- append_head
632
- append_pathspec files
767
+ out = option_sanitize(opts, OPT_GIT[:checkout], no: OPT_GIT[:no][:checkout]).first
768
+ if flag == :commit
769
+ append_value(commit, delim: true)
770
+ option_clear out
771
+ else
772
+ append_head
773
+ append_pathspec out
774
+ end
633
775
  end
634
776
  source
635
777
  end
636
778
 
637
- def tag(flag, refs, message: nil, commit: nil)
779
+ def tag(flag, opts = [], refs: [], message: nil, commit: nil)
638
780
  cmd = git_session 'tag'
639
781
  case flag
640
782
  when :add
641
783
  if option('sign')
642
784
  cmd << '--sign'
643
- else
644
- out = cmd.to_s
645
- cmd << '--annotate' if %w[-s --sign -u --local-user].none? { |val| out.include?(" #{val}") }
785
+ elsif !session_arg?('s', 'sign', 'u', 'local-user')
786
+ cmd << '--annotate'
646
787
  end
647
788
  if !commit && message && (hash = commithash(message))
648
789
  commit = hash
649
790
  else
650
791
  append_message message
651
792
  end
652
- append_value(refs, escape: false)
793
+ append_value refs
653
794
  append_head commit
654
- when :delete, :list, :merged
795
+ when :list
796
+ cmd << '--list'
797
+ grep = option_sanitize(opts, OPT_GIT[:tag], no: OPT_GIT[:no][:tag]).first
798
+ out, banner, from = source(io: true)
799
+ print_item banner
800
+ ret = write_lines(out, grep: grep)
801
+ list_result(ret, 'tags', from: from, grep: grep)
802
+ return
803
+ when :delete
804
+ cmd << '--delete'
805
+ append_value refs
806
+ else
655
807
  cmd << shell_option(flag, commit)
656
- append_option(%w[contains sort] + (flag == :list ? ['merged'] : []), equals: true) unless flag == :delete
657
- append_value(refs, escape: false)
658
808
  end
659
809
  source
660
810
  end
661
811
 
662
- def diff(flag, files = [], branch: nil, index: 0, range: [])
812
+ def logx(flag, opts = [], range: [])
813
+ cmd = git_session 'log'
814
+ files = option_sanitize(opts, collect_hash(OPT_GIT[:log]), no: collect_hash(OPT_GIT[:no][:log])).first
815
+ case flag
816
+ when :between, :contain
817
+ cmd << shell_quote(range.join(flag == :between ? '..' : '...'))
818
+ else
819
+ commit, files = files.partition do |val|
820
+ val.start_with?('^') || (!%r{^[.\\/]}.match?(val) && !%r{[\\/]$}.match?(val)) || commithash(val)
821
+ end
822
+ cmd.merge(commit.map { |val| commithash(val) || shell_quote(val) }) unless commit.empty?
823
+ end
824
+ append_nocolor
825
+ append_pathspec files
826
+ source(exception: false)
827
+ end
828
+
829
+ def diff(flag, opts = [], refs: [], branch: nil, range: [])
663
830
  cmd = git_session 'diff'
664
- sha = []
831
+ files = option_sanitize(opts, collect_hash(OPT_GIT[:diff]) + OPT_GIT[:log][:diff],
832
+ no: OPT_GIT[:no][:log][:diff]).first
665
833
  case flag
666
- when :files, :between, :contain
834
+ when :files, :view, :between, :contain
667
835
  cmd.delete('--cached')
668
836
  else
669
837
  items = files.dup
838
+ sha = nil
670
839
  files.clear
671
840
  items.each do |val|
672
- if (hash = commithash(val))
673
- sha << hash
841
+ if (s = commithash(val))
842
+ (sha ||= []).push(s)
674
843
  else
675
844
  files << val
676
845
  end
677
846
  end
678
847
  end
679
- if (val = option('unified')).to_i > 0
680
- cmd << basic_option('unified', val)
681
- end
682
848
  append_nocolor
683
- case flag
684
- when :cached
685
- cmd << '--cached'
686
- cmd << '--merge-base' if option('merge-base')
687
- when :branch
688
- cmd << branch
689
- when :files
849
+ if flag == :files
690
850
  cmd << '--no-index'
691
- when :between, :contain
692
- cmd << shell_quote(range.join(flag == :between ? '..' : '...'))
851
+ append_pathspec(refs, parent: true)
693
852
  else
694
- if (val = option('index')) || index > 0
695
- cmd << "HEAD~#{val || index}"
696
- elsif !sha.empty? && option('merge-base')
697
- cmd << '--merge-base'
698
- end
699
- end
700
- unless sha.empty?
701
- if cmd.include?('--cached')
702
- raise_error('diff', sha.join(', '), hint: 'one commit') if sha.size > 1
703
- cmd << sha.first
853
+ case flag
854
+ when :view
855
+ cmd << '--merge-base' if option('merge-base')
856
+ cmd << shell_quote(range.first, quote: true) << shell_quote(range.last, quote: true)
857
+ when :between, :contain
858
+ cmd.delete('--merge-base')
859
+ cmd << shell_quote(range.join(flag == :between ? '..' : '...'))
704
860
  else
705
- cmd.merge(sha)
861
+ cmd << '--cached' if flag == :cached
862
+ cmd << '--merge-base' if option('merge-base')
863
+ cmd << shell_quote(branch) if branch
864
+ if sha
865
+ if session_arg?('cached')
866
+ raise_error('diff', sha.join(', '), hint: 'one commit') if sha.size > 1
867
+ cmd << sha.first
868
+ else
869
+ cmd.merge(sha)
870
+ end
871
+ elsif (n = option('index'))
872
+ cmd << "HEAD~#{n}"
873
+ end
706
874
  end
875
+ append_pathspec files
707
876
  end
708
- append_pathspec(files, parent: flag == :files)
709
- source(exception: cmd.include?('--exit-code'))
877
+ source(exception: session_arg?('exit-code'))
710
878
  end
711
879
 
712
- def commit(flag, files = [], message: nil, pass: false)
880
+ def commit(flag, *, refs: [], message: nil, pass: false)
713
881
  message ||= option('message', 'm', prefix: 'git', ignore: false)
714
882
  amend = flag.to_s.start_with?('amend')
715
883
  if !message && !amend
@@ -717,45 +885,59 @@ module Squared
717
885
 
718
886
  raise_error('commit', 'GIT_MESSAGE="description"', hint: 'missing')
719
887
  end
720
- pathspec = if flag == :all || (amend && files.size == 1 && files.first == '*')
888
+ pathspec = if flag == :all || (amend && refs.size == 1 && refs.first == '*')
721
889
  '--all'
890
+ elsif (refs = projectmap(refs)).empty?
891
+ raise_error('commit', 'pathspec', hint: 'missing')
722
892
  else
723
- raise_error('commit', 'pathspec', hint: 'missing') if (files = projectmap(files)).empty?
724
- "-- #{files.join(' ')}"
893
+ "-- #{refs.join(' ')}"
725
894
  end
726
- format = '%(if)%(HEAD)%(then)%(refname:short)...%(upstream:short)...%(upstream:track)%(end)'
727
- branch = nil
728
895
  origin = nil
729
- source(git_output('fetch --no-tags --quiet'), io: true, banner: false, stdout: true)
730
- cmd = git_output("for-each-ref --format=\"#{format}\" refs/heads")
731
- source(cmd, io: true, banner: false).first.each do |line|
732
- next if (line = line.chomp).empty?
733
-
734
- branch, origin, hint = line.split('...')
735
- if hint && !hint.match?(/^\[(\D+0,\D+0)\]$/)
736
- raise_error('work tree is not usable', hint: hint[1..-2])
737
- elsif origin.empty?
738
- return nil if pass
739
-
740
- raise_error('no remote upstream', hint: branch)
896
+ branch = nil
897
+ upstream = nil
898
+ source(git_output('fetch', '--no-tags', '--quiet'), io: true, banner: false)
899
+ source(git_output('branch', '-vv', '--list'), io: true, banner: false).first.each do |val|
900
+ next unless (data = /^\*\s(\S+)\s+(\h+)(?:\s\[(.+?)(?=\]\s)\])?\s/.match(val))
901
+
902
+ branch = data[1]
903
+ if !data[3]
904
+ unless (origin = option('repository', prefix: 'git', ignore: false))
905
+ out = source(git_output('log', '-n1', '--format=%h%d'), io: true, stdout: true, banner: false).first
906
+ if out =~ /^#{data[2]} \(HEAD -> #{Regexp.escape(branch)}, (.+?)\)$/
907
+ split_escape($1).each do |val|
908
+ next unless val.end_with?("/#{branch}")
909
+
910
+ origin = val[0, val.size - branch.size - 1]
911
+ break
912
+ end
913
+ end
914
+ end
915
+ upstream = true if origin
916
+ elsif data[3] =~ %r{^(.+)/#{Regexp.escape(branch)}$}
917
+ origin = $1
741
918
  end
742
919
  break
743
920
  end
744
- i = origin.index('/')
745
- branch = "#{branch}:#{origin[i + 1..-1]}" unless origin.end_with?("/#{branch}")
746
- origin = origin[0..i - 1]
921
+ raise_error('commit', 'work tree is not usable') unless origin && branch
747
922
  cmd = git_session('commit', option('dry-run') && '--dry-run', options: false)
748
- cmd << '--amend' if amend
923
+ if amend
924
+ cmd << '--amend'
925
+ else
926
+ cmd.delete('--amend')
927
+ end
749
928
  if message
750
929
  append_message message
751
930
  elsif flag == :'amend-orig' || option('no-edit')
752
931
  cmd << '--no-edit'
753
932
  end
754
933
  a = git_output 'add', '--verbose'
755
- b = git_output 'push'
756
- b << '--dry-run' if dryrun?
934
+ b = git_output 'push', upstream && '--set-upstream'
935
+ if dryrun?
936
+ a << '--dry-run'
937
+ b << '--dry-run'
938
+ end
757
939
  a << pathspec
758
- b << '--force-with-lease' if amend
940
+ b << '--force' if amend
759
941
  b << origin << branch
760
942
  puts if pass
761
943
  source a
@@ -763,7 +945,7 @@ module Squared
763
945
  source b
764
946
  end
765
947
 
766
- def branch(flag, names = [], target: nil, ref: nil, opts: [])
948
+ def branch(flag, opts = [], refs: [], ref: nil, target: nil)
767
949
  cmd = git_session 'branch'
768
950
  stdout = false
769
951
  case flag
@@ -780,8 +962,10 @@ module Squared
780
962
  end
781
963
  cmd << '--force' if option('force')
782
964
  when :set
783
- if ref.start_with?('!')
784
- cmd << '--unset-upstream' << shell_escape(ref[1..-1])
965
+ return unless ref
966
+
967
+ if ref.start_with?('^')
968
+ cmd << '--unset-upstream' << shell_escape(arg[1..-1])
785
969
  target = nil
786
970
  stdout = true
787
971
  else
@@ -789,9 +973,9 @@ module Squared
789
973
  end
790
974
  ref = nil
791
975
  when :delete
792
- force, list = names.partition { |val| val =~ /^[\^~]/ }
976
+ force, list = refs.partition { |val| val =~ /^[\^~]/ }
793
977
  force.each do |val|
794
- dr = val[0..2]
978
+ dr = val[0, 3]
795
979
  d = dr.include?('^') ? '-D' : '-d'
796
980
  r = dr.include?('~') ? '-r' : nil
797
981
  source git_output('branch', d, r, shell_quote(val.sub(/^[\^~]+/, '')))
@@ -803,27 +987,18 @@ module Squared
803
987
  when :move, :copy
804
988
  flag = "-#{flag.to_s[0]}"
805
989
  cmd << (option('force') ? flag.upcase : flag)
806
- names.compact.each { |val| cmd << shell_quote(val) }
990
+ refs.compact.each { |val| cmd << shell_quote(val) }
807
991
  stdout = true
808
992
  when :edit
809
993
  cmd << '--edit-description'
810
994
  when :current
811
995
  cmd << '--show-current'
812
996
  else
813
- opts, pat = option_partition(opts, OPT_BRANCH, no: NO_BRANCH)
997
+ opts = option_sanitize(opts, OPT_GIT[:branch], no: OPT_GIT[:no][:branch]).first
814
998
  grep = []
815
999
  opts.each do |opt|
816
1000
  if opt =~ /^(v+)$/
817
1001
  cmd << "-#{$1}"
818
- elsif opt =~ pat
819
- case $1
820
- when 'column', 'format'
821
- cmd << quote_option($1, $2)
822
- when 'abbrev'
823
- cmd << basic_option($1, $2) if $2.to_i > 0
824
- else
825
- cmd << shell_option($1, $2)
826
- end
827
1002
  else
828
1003
  grep << opt
829
1004
  end
@@ -844,16 +1019,24 @@ module Squared
844
1019
  source(stdout: stdout)
845
1020
  end
846
1021
 
847
- def restore(flag, files, tree: nil)
848
- source = flag == :source
849
- cmd = git_session 'restore', source && files.empty? ? '--patch' : nil, shell_option(flag, tree)
850
- append_option %w[staged worktree]
851
- append_first %w[ours theirs]
852
- append_pathspec(files, expect: !cmd.include?('--patch'))
853
- source(stdout: !source)
1022
+ def restore(flag, opts = [], tree: nil)
1023
+ cmd = git_session 'restore'
1024
+ refs = option_sanitize(opts, OPT_GIT[:restore], no: OPT_GIT[:no][:restore]).first
1025
+ if flag == :source
1026
+ cmd << '--patch' if refs.empty?
1027
+ cmd << shell_option('source', tree)
1028
+ else
1029
+ cmd << "--#{flag}"
1030
+ end
1031
+ if session_arg?('p', 'patch')
1032
+ option_clear refs
1033
+ else
1034
+ append_pathspec(refs, expect: true)
1035
+ end
1036
+ source(sync: false, stderr: true)
854
1037
  end
855
1038
 
856
- def show(objs, format: nil, opts: nil)
1039
+ def show(format, opts = [])
857
1040
  cmd = git_session 'show'
858
1041
  if format
859
1042
  case (val = format.downcase)
@@ -863,41 +1046,54 @@ module Squared
863
1046
  if format =~ /^t?format:/ || format.include?('%')
864
1047
  cmd << quote_option('pretty', format)
865
1048
  else
866
- objs << format
1049
+ opts << format
867
1050
  end
868
1051
  end
869
1052
  end
870
- if opts
871
- append_hash opts
872
- banner = format != 'oneline'
873
- else
1053
+ refs = option_sanitize(opts, OPT_GIT[:show] + OPT_GIT[:diff][:show] + OPT_GIT[:log][:diff],
1054
+ no: OPT_GIT[:no][:show] + collect_hash(OPT_GIT[:no][:log], pass: [:base])).first
1055
+ unless val == 'oneline' && session_arg?('abbrev-commit')
874
1056
  cmd << basic_option('abbrev', val) if (val = option('abbrev')) && val.to_i > 0
875
1057
  banner = true
876
1058
  end
877
- append_value(objs, delim: true)
1059
+ append_value(refs, delim: true)
878
1060
  source(exception: false, banner: banner)
879
1061
  end
880
1062
 
881
- def rev_parse(flag, ref: nil, size: nil)
882
- git_session 'rev-parse', if flag == :branch
883
- '--abbrev-ref'
884
- else
885
- (n = size.to_i) > 0 ? basic_option('short', [n, 5].max) : '--verify'
886
- end
887
- append_commit ref
888
- source
1063
+ def rev_parse(flag, opts = [], ref: nil, size: nil)
1064
+ cmd = git_session 'rev-parse', if flag == :parseopt
1065
+ '--parseopt'
1066
+ elsif opts.delete('sq-quote')
1067
+ '--sq-quote'
1068
+ end
1069
+ case flag
1070
+ when :commit
1071
+ cmd << ((n = size.to_i) > 0 ? basic_option('short', [n, 5].max) : '--verify')
1072
+ append_commit ref
1073
+ when :branch
1074
+ cmd << '--abbrev-ref'
1075
+ append_commit ref
1076
+ else
1077
+ args = option_sanitize(opts, OPT_GIT[:rev_parse][flag]).first
1078
+ append_value(args, escape: session_arg?('sq-quote'))
1079
+ end
1080
+ source(banner: verbose == 1)
889
1081
  end
890
1082
 
891
- def ls_remote(flag, grep: nil)
892
- git_session 'ls-remote', "--#{flag}", '--refs'
1083
+ def ls_remote(flag, opts = [], remote: nil)
1084
+ cmd = git_session 'ls-remote', '--refs'
1085
+ cmd << "--#{flag}" unless flag == :remote
1086
+ grep = option_sanitize(opts, OPT_GIT[:ls_remote]).first
1087
+ cmd << shell_quote(remote) if remote
893
1088
  out, banner, from = source(io: true)
894
1089
  print_item banner
895
1090
  ret = write_lines(out, grep: grep)
896
1091
  list_result(ret, flag.to_s, from: from, grep: grep)
897
1092
  end
898
1093
 
899
- def ls_files(flag, grep: nil)
1094
+ def ls_files(flag, opts = [])
900
1095
  git_session 'ls-files', "--#{flag}"
1096
+ grep = option_sanitize(opts, OPT_GIT[:ls_files]).first
901
1097
  out, banner, from = source(io: true)
902
1098
  print_item banner
903
1099
  ret = write_lines(out, grep: grep)
@@ -924,8 +1120,8 @@ module Squared
924
1120
  banner &&= cmd.temp { |val| val.start_with?('--work-tree') || val.start_with?('--git-dir') }
925
1121
  end
926
1122
  cmd = session_done(cmd)
927
- log&.info cmd
928
- on :first, from if from
1123
+ log.info cmd
1124
+ on :first, from
929
1125
  banner = if banner
930
1126
  format_banner((banner.is_a?(String) ? banner : cmd).gsub(File.join(path, ''), ''), banner: true)
931
1127
  end
@@ -960,26 +1156,32 @@ module Squared
960
1156
  end
961
1157
  end
962
1158
  rescue StandardError => e
963
- log&.error e
964
- ret = on(:error, from, e) if from
1159
+ log.error e
1160
+ ret = on(:error, from, e)
965
1161
  raise if exception && ret != true
966
1162
 
967
1163
  warn log_message(Logger::WARN, e) if warning?
968
1164
  else
969
- on :last, from if from
1165
+ on :last, from
970
1166
  end
971
1167
  end
972
1168
 
973
1169
  def write_lines(data, banner: nil, loglevel: nil, grep: nil, sub: nil, pass: false)
974
- grep = Regexp.new(grep == '*' ? '.+' : grep) if grep.is_a?(String)
1170
+ grep = if grep && !grep.empty?
1171
+ as_a(grep).map do |val|
1172
+ next val if val.is_a?(Regexp)
1173
+
1174
+ Regexp.new(val == '*' ? '.+' : val.to_s)
1175
+ end
1176
+ end
975
1177
  sub = nil if stdin?
976
1178
  ret = 0
977
1179
  out = []
978
1180
  data.each do |line|
979
- next if grep && !line.match?(grep)
1181
+ next if grep&.none? { |pat| pat.match?(line) }
980
1182
 
981
1183
  if loglevel
982
- log&.add loglevel, line
1184
+ log.add loglevel, line
983
1185
  else
984
1186
  sub&.each { |h| line = sub_style(line, **h) }
985
1187
  if banner
@@ -999,38 +1201,37 @@ module Squared
999
1201
  if size > 0
1000
1202
  styles = theme.fetch(:banner, []).reject { |s| s.to_s.end_with?('!') }
1001
1203
  styles << :bold if styles.size <= 1
1002
- puts print_footer("#{size} #{size == 1 ? type.sub(/(?:(?<!l)e)?s\z/, '') : type}",
1204
+ puts print_footer("#{size} #{size == 1 ? type.sub(/s\z/, '') : type}",
1003
1205
  sub: { pat: /\A(\d+)(.+)\z/, styles: styles })
1004
1206
  else
1005
- puts empty_status("No #{type} were #{action}", 'grep', grep)
1207
+ puts empty_status("No #{type} were #{action}", 'grep', grep.is_a?(Array) ? case grep.size
1208
+ when 0
1209
+ nil
1210
+ else
1211
+ grep.join(', ')
1212
+ end : grep.to_s)
1006
1213
  end
1007
1214
  end
1008
- on :last, from if from
1215
+ on :last, from
1009
1216
  end
1010
1217
 
1011
- def append_pull(opts, list, no = [], target: @session, flag: nil, remote: nil)
1012
- target << '--force' if option('force', target: target)
1013
- modules = append_submodules(target: target)
1218
+ def append_pull(opts, list, target: @session, no: nil, flag: nil, remote: nil)
1219
+ cmd << '--force' if option('force')
1220
+ rsm = append_submodules(target: target)
1014
1221
  out = []
1015
1222
  refspec = []
1016
- opts, pat = option_partition(opts, remote ? list + ['refspec=s'] : list, target: target, no: no)
1223
+ opts, pat = option_sanitize(opts, remote ? list + ['refspec=s'] : list, target: target, no: no)
1017
1224
  opts.each do |opt|
1018
1225
  if opt =~ pat
1019
1226
  case $1
1020
1227
  when 'rebase'
1021
- target << basic_option($1, $2) if VAL_REBASE.include?($2)
1228
+ target << basic_option($1, $2) if VAL_GIT[:rebase][:value].include?($2)
1022
1229
  when 'shallow-since'
1023
1230
  next unless (val = Date.parse($2))
1024
1231
 
1025
1232
  target << quote_option($1, val.strftime('%F %T'))
1026
1233
  when 'recurse-submodules'
1027
- target << basic_option($1, $2) unless modules
1028
- when 'shallow-exclude', 'gpg-sign', 'signoff', 'strategy', 'strategy-option'
1029
- target << shell_option($1, $2)
1030
- when 'refmap', 'negotiation-tip'
1031
- target << quote_option($1, $2)
1032
- when 'depth', 'deepen', 'log', 'jobs'
1033
- target << basic_option($1, $2) if $2.to_i > 0
1234
+ target << basic_option($1, $2) unless rsm
1034
1235
  when 'refspec'
1035
1236
  refspec << shell_escape($2, quote: true)
1036
1237
  end
@@ -1039,9 +1240,9 @@ module Squared
1039
1240
  end
1040
1241
  end
1041
1242
  if remote
1042
- append_value(remote, target: target, delim: true, quote: true)
1043
- if (val = option('refspec', target: target, strict: true))
1044
- append_value(split_escape(val), target: target, escape: false)
1243
+ append_value(remote, target: target, delim: true)
1244
+ if (val = option('refspec', strict: true))
1245
+ append_value(split_escape(val), target: target)
1045
1246
  else
1046
1247
  target.merge(refspec)
1047
1248
  end
@@ -1059,47 +1260,45 @@ module Squared
1059
1260
  end
1060
1261
 
1061
1262
  def append_pathspec(files = [], target: @session, expect: false, parent: false)
1062
- if files.empty? && (val = option('pathspec', target: target))
1063
- files = split_escape(val)
1064
- end
1065
- files = projectmap(files, parent: parent)
1066
- if !files.empty?
1067
- target << "-- #{files.join(' ')}"
1068
- elsif expect
1069
- raise_error(parent ? 'pathspec not present' : 'pathspec not within worktree', hint: 'invalid')
1263
+ if session_arg?('pathspec-from-file')
1264
+ option_clear files
1265
+ else
1266
+ if files.empty? && (val = option('pathspec'))
1267
+ files = split_escape(val)
1268
+ end
1269
+ files = projectmap(files, parent: parent)
1270
+ if !files.empty?
1271
+ target << "-- #{files.join(' ')}"
1272
+ elsif expect
1273
+ raise_error(parent ? 'pathspec not present' : 'pathspec not within worktree', hint: 'invalid')
1274
+ end
1070
1275
  end
1071
1276
  end
1072
1277
 
1073
1278
  def append_message(val, target: @session)
1074
- target << "--message=\"#{double_quote(val)}\"" unless val.to_s.empty?
1279
+ target << quote_option('message', val) unless val.to_s.empty?
1075
1280
  end
1076
1281
 
1077
1282
  def append_head(val = nil, target: @session)
1078
1283
  return target << val if val
1079
1284
 
1080
- append_first(%w[head tree-ish object], target: target, flag: false, ignore: false)
1285
+ append_first('head', 'tree-ish', 'object', target: target, flag: false, ignore: false)
1081
1286
  end
1082
1287
 
1083
1288
  def append_submodules(from = nil, target: @session)
1084
- return unless (val = option('recurse-submodules', target: target, ignore: false))
1289
+ return unless (val = option('recurse-submodules', ignore: false))
1085
1290
 
1086
1291
  if from == :clone
1087
- case val
1088
- when '0', 'false'
1089
- target << '--no-recurse-submodules'
1090
- when '1', 'true'
1091
- target << '--recurse-submodules'
1092
- else
1093
- projectmap(split_escape(val)).each do |path|
1094
- target << basic_option('recurse-submodules', path)
1095
- end
1292
+ projectmap(split_escape(val)).each do |path|
1293
+ target << basic_option('recurse-submodules', path)
1096
1294
  end
1295
+ target
1097
1296
  else
1098
1297
  target << case val
1099
1298
  when 'no', '0'
1100
1299
  '--no-recurse-submodules'
1101
1300
  when 'yes', 'on-demand'
1102
- "--recurse-submodules=#{val}"
1301
+ "--recurse-submodules#{from == :reset ? '' : "=#{val}"}"
1103
1302
  else
1104
1303
  '--recurse-submodules'
1105
1304
  end
@@ -1115,8 +1314,14 @@ module Squared
1115
1314
  git_session(*cmd, main: false, options: false, **kwargs)
1116
1315
  end
1117
1316
 
1118
- def dryrun?(*)
1119
- !!@session&.include?('--dry-run')
1317
+ def dryrun?(*, target: @session, **)
1318
+ !!target&.include?('--dry-run')
1319
+ end
1320
+
1321
+ def quiet?(target: @session)
1322
+ return false unless target
1323
+
1324
+ target.include?('--quiet') || (target.include?('-q') && target.first == 'git')
1120
1325
  end
1121
1326
 
1122
1327
  def gitpath
@@ -1124,7 +1329,7 @@ module Squared
1124
1329
  end
1125
1330
 
1126
1331
  def commithash(val)
1127
- (data = /\A#\{(\h{5,40})\}\z/.match(val)) ? data[1] : nil
1332
+ val =~ /\A#\{(\h{5,40})\}\z/ ? $1 : nil
1128
1333
  end
1129
1334
 
1130
1335
  def threadargs