squared 0.2.11 → 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.
@@ -12,11 +12,7 @@ module Squared
12
12
  check = ->(proj) { proj.is_a?(Project::Git) && !proj.exclude?(Project::Git.ref) && git_clone?(proj.path) }
13
13
  if uri.is_a?(Array)
14
14
  base = name
15
- uri.each do |val|
16
- if (proj = @project[val.to_s]) && check.(proj)
17
- repo << proj
18
- end
19
- end
15
+ uri.each { |val| repo << proj if (proj = @project[val.to_s]) && check.(proj) }
20
16
  elsif uri
21
17
  data[name.to_s] = uri
22
18
  elsif name.is_a?(Enumerable)
@@ -76,23 +72,111 @@ module Squared
76
72
 
77
73
  module Project
78
74
  class Git < Base
79
- FOR_FETCH = %w[atomic multiple negotiate-only prefetch progress prune-tags refetch].freeze
80
- NO_FETCH = %w[all ipv4 ipv6 recurse-submodules show-forced-updates tags].freeze
81
- FNO_FETCH = %w[auto-gc auto-maintenance write-commit-graph write-fetch-head].freeze
82
- OPT_FETCH = (FOR_FETCH + NO_FETCH + FNO_FETCH +
83
- %w[append dry-run force keep prune quiet set-upstream unshallow update-shallow verbose
84
- deepen=i depth=i jobs=i negotiation-tip=s refmap=s recurse-submodules=s server-option=s
85
- shallow-exclude=s shallow-since=d upload-pack=s]).freeze
86
- NO_PULL = %w[allow-unrelated-histories autostash commit edit ff signoff squash stat verify verify-signatures
87
- gpg-sign=? log=? rebase=?].freeze
88
- OPT_PULL = (NO_PULL + %w[ff-only signoff=s strategy=s strategy-option=s]).freeze
89
- OPT_REBASE = %w[continue skip abort quit].freeze
90
- VAL_REBASE = %w[true false merges interactive].freeze
91
- NO_BRANCH = %w[abbrev=i color=? column=? track=?].freeze
92
- OPT_BRANCH = (NO_BRANCH + %w[all create-reflog ignore-case quiet remotes verbose
93
- contains=s format=s merged=s no-contains=s no-merged=s points-at=s sort=s]).freeze
94
- private_constant :FOR_FETCH, :NO_FETCH, :FNO_FETCH, :OPT_FETCH, :NO_PULL, :OPT_PULL, :OPT_REBASE, :VAL_REBASE,
95
- :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
96
180
 
97
181
  class << self
98
182
  include Rake::DSL
@@ -138,21 +222,22 @@ module Squared
138
222
  end
139
223
 
140
224
  @@tasks[ref] = {
141
- 'checkout' => %i[branch track detach force merge].freeze,
142
- 'commit' => %i[add amend amend-orig all no-all].freeze,
143
- 'diff' => %i[head cached branch files between contain].freeze,
144
- 'pull' => %i[origin remote].freeze,
145
- 'fetch' => %i[origin remote].freeze,
146
- 'stash' => %i[push pop apply list clear].freeze,
147
- 'rebase' => %i[onto root send].freeze,
148
225
  'branch' => %i[create set delete move copy list edit current].freeze,
149
- 'refs' => %i[heads tags].freeze,
150
- 'files' => %i[cached modified deleted others].freeze,
151
- '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,
152
236
  'restore' => %i[source worktree staged overlay].freeze,
153
- 'rev' => %i[commit branch].freeze,
237
+ 'rev' => %i[commit branch output parseopt].freeze,
154
238
  'show' => %i[format oneline].freeze,
155
- 'tag' => %i[add delete list merged].freeze
239
+ 'stash' => %i[push pop apply drop list].freeze,
240
+ 'tag' => %i[add delete list].freeze
156
241
  }.freeze
157
242
 
158
243
  def initialize(*, **)
@@ -177,93 +262,96 @@ module Squared
177
262
  case action
178
263
  when 'pull', 'fetch'
179
264
  if flag == :remote
180
- if @@task_desc
181
- format_desc(action, flag, ['refspec=s'] + (action == 'pull' ? OPT_PULL : OPT_FETCH),
182
- before: 'remote')
183
- end
265
+ format_desc(action, flag, 'remote,opts*')
184
266
  task flag, [:remote] do |_, args|
185
267
  remote = param_guard(action, flag, args: args, key: :remote)
186
- __send__(action, flag, remote: remote, opts: args.extras)
268
+ __send__(action, flag, args.extras, remote: remote)
187
269
  end
188
270
  else
189
- format_desc(action, flag, action == 'pull' ? OPT_PULL : OPT_FETCH)
271
+ format_desc action, flag, 'opts*'
190
272
  task flag do |_, args|
191
- __send__(action, flag, opts: args.to_a)
273
+ __send__ action, flag, args.to_a
192
274
  end
193
275
  end
194
- when 'commit', 'restore'
276
+ when 'commit'
195
277
  case flag
196
278
  when :all
197
279
  format_desc action, flag, 'message?'
198
280
  task flag, [:message] do |_, args|
199
281
  commit(flag, message: args.fetch(:message, nil))
200
282
  end
201
- when :source
202
- 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*'
203
293
  task flag, [:tree] do |_, args|
204
294
  tree = param_guard(action, flag, args: args, key: :tree)
205
295
  restore(flag, args.extras, tree: tree)
206
296
  end
207
297
  else
208
- format_desc action, flag, 'pathspec+'
298
+ format_desc action, flag, 'opts*,pathspec+'
209
299
  task flag do |_, args|
210
- files = param_guard(action, flag, args: args.to_a)
211
- __send__ action, flag, files
300
+ restore flag, args.to_a
212
301
  end
213
302
  end
214
303
  when 'tag'
215
304
  case flag
216
305
  when :list
217
- format_desc action, flag, 'pattern*'
306
+ format_desc action, flag, 'opts*,pattern*'
218
307
  task flag do |_, args|
219
308
  tag flag, args.to_a
220
309
  end
221
- when :merged
222
- format_desc action, flag, 'commit,pattern*'
223
- task flag, [:commit] do |_, args|
224
- commit = param_guard(action, flag, args: args, key: :commit)
225
- tag(flag, args.extras, commit: commit)
226
- end
227
310
  when :delete
228
311
  format_desc action, flag, 'name+'
229
312
  task flag do |_, args|
230
- name = param_guard(action, flag, args: args.to_a)
231
- tag flag, name
313
+ refs = param_guard(action, flag, args: args.to_a)
314
+ tag(flag, refs: refs)
232
315
  end
233
316
  when :add
234
317
  format_desc action, flag, 'name,message?,commit?'
235
318
  task flag, [:name, :message, :commit] do |_, args|
236
319
  name = param_guard(action, flag, args: args, key: :name)
237
- tag(flag, [name], message: args.message, commit: args.commit)
320
+ tag(flag, refs: [name], message: args.message, commit: args.commit)
238
321
  end
239
322
  end
240
323
  when 'stash'
241
- if flag == :push
242
- format_desc action, flag, 'pathspec*'
243
- task flag do |_, args|
244
- stash flag, args.to_a
245
- end
324
+ if flag == :list
325
+ format_desc action, flag
246
326
  else
247
- format_desc action, flag, 'commit?'
248
- task flag, [:commit] do |_, args|
249
- stash(flag, commit: args.commit)
250
- end
327
+ format_desc(action, flag, '*opts', after: flag == :push ? 'pathspec*' : 'commit?')
328
+ end
329
+ task flag do |_, args|
330
+ stash flag, args.to_a
251
331
  end
252
- when 'diff'
332
+ when 'log', 'diff'
253
333
  case flag
254
- when :head
255
- format_desc action, flag, 'index?=0,pathspec*'
256
- task flag do |_, args|
257
- files = args.to_a
258
- 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
259
347
  end
260
- when :cached
261
- format_desc action, flag, 'pathspec*'
348
+ when :head, :cached
349
+ format_desc action, flag, 'opts*,pathspec*'
262
350
  task flag do |_, args|
263
351
  diff flag, args.to_a
264
352
  end
265
353
  when :branch
266
- format_desc action, flag, 'name,pathspec*'
354
+ format_desc action, flag, 'name,opts*,pathspec*'
267
355
  task flag, [:name] do |_, args|
268
356
  branch = param_guard(action, flag, args: args, key: :name)
269
357
  diff(flag, args.extras, branch: branch)
@@ -273,14 +361,7 @@ module Squared
273
361
  task flag, [:path1, :path2] do |_, args|
274
362
  path1 = param_guard(action, flag, args: args, key: :path1)
275
363
  path2 = param_guard(action, flag, args: args, key: :path2)
276
- diff flag, [path1, path2]
277
- end
278
- else
279
- format_desc action, flag, 'commit1,commit2,pathspec*'
280
- task flag, [:commit1, :commit2] do |_, args|
281
- commit1 = param_guard(action, flag, args: args, key: :commit1)
282
- commit2 = param_guard(action, flag, args: args, key: :commit2)
283
- diff(flag, args.extras, range: [commit1, commit2])
364
+ diff(flag, refs: [path1, path2])
284
365
  end
285
366
  end
286
367
  when 'checkout'
@@ -314,13 +395,19 @@ module Squared
314
395
  origin = param_guard(action, flag, args: args, key: :origin)
315
396
  checkout(flag, branch: args.name, origin: origin)
316
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
317
404
  when :detach
318
405
  format_desc action, flag, 'branch/commit?'
319
406
  task flag, [:commit] do |_, args|
320
407
  checkout(flag, commit: args.commit)
321
408
  end
322
- else
323
- format_desc action, flag, 'pathspec*'
409
+ when :path
410
+ format_desc action, flag, 'opts*,pathspec*'
324
411
  task flag do |_, args|
325
412
  checkout flag, args.to_a
326
413
  end
@@ -330,11 +417,11 @@ module Squared
330
417
  when :create
331
418
  format_desc action, flag, 'name,ref?=HEAD'
332
419
  task flag, [:name, :ref] do |_, args|
333
- name = param_guard(action, flag, args: args, key: :name)
334
- 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)
335
422
  end
336
423
  when :set
337
- format_desc(action, flag, '(!)upstream,name?')
424
+ format_desc(action, flag, '(^)upstream,name?')
338
425
  task flag, [:upstream, :name] do |_, args|
339
426
  upstream = param_guard(action, flag, args: args, key: :upstream)
340
427
  branch(flag, target: args.name, ref: upstream)
@@ -342,8 +429,8 @@ module Squared
342
429
  when :delete
343
430
  format_desc action, flag, '(^~)name+'
344
431
  task flag, [:name] do |_, args|
345
- name = param_guard(action, flag, args: args.to_a)
346
- branch flag, name
432
+ refs = param_guard(action, flag, args: args.to_a)
433
+ branch(flag, refs: refs)
347
434
  end
348
435
  when :edit
349
436
  format_desc action, flag, 'name?'
@@ -351,9 +438,9 @@ module Squared
351
438
  branch(flag, target: args.name)
352
439
  end
353
440
  when :list
354
- format_desc(action, flag, OPT_BRANCH, before: 'pattern*')
441
+ format_desc action, flag, 'opts*,pattern*'
355
442
  task flag do |_, args|
356
- branch(flag, opts: args.to_a)
443
+ branch flag, args.to_a
357
444
  end
358
445
  when :current
359
446
  format_desc action, flag
@@ -361,74 +448,109 @@ module Squared
361
448
  branch flag
362
449
  end
363
450
  else
364
- format_desc action, flag, 'newbranch,oldbranch?'
365
- task flag, [:newbranch, :oldbranch] do |_, args|
366
- newbranch = param_guard(action, flag, args: args, key: :newbranch)
367
- 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])
368
455
  end
369
456
  end
370
457
  when 'reset'
371
458
  case flag
372
- when :mode
373
- if @@task_desc
374
- format_desc(action, flag, %w[soft mixed hard merge keep {no-}submodules], after: 'ref?=HEAD',
375
- 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
376
469
  end
470
+ when :mode
471
+ format_desc action, flag, 'mode,ref?=HEAD'
377
472
  task flag, [:mode, :ref] do |_, args|
378
473
  mode = param_guard(action, flag, args: args, key: :mode)
379
474
  reset(flag, mode: mode, ref: args.ref)
380
475
  end
381
- else
382
- format_desc action, flag, 'ref,pathspec+'
476
+ when :patch
477
+ format_desc action, flag, 'ref,pathspec*'
383
478
  task flag, [:ref] do |_, args|
384
- files = param_guard(action, flag, args: args.extras)
385
- reset(flag, files, ref: args.ref)
479
+ ref = param_guard(action, flag, args: args, key: :ref)
480
+ reset(flag, refs: args.extras, ref: ref)
386
481
  end
387
482
  end
388
483
  when 'show'
389
484
  case flag
390
485
  when :oneline
391
- format_desc action, flag, 'object*'
486
+ format_desc action, flag, 'opts*,object*'
392
487
  task flag do |_, args|
393
- show(args.to_a, format: 'oneline', opts: { 'abbrev-commit': true })
488
+ show 'oneline', args.to_a.push('abbrev-commit')
394
489
  end
395
490
  when :format
396
- format_desc action, flag, 'format?,object*'
491
+ format_desc action, flag, 'format?,opts*,object*'
397
492
  task flag, [:format] do |_, args|
398
- show(args.extras, format: args.format)
493
+ show args.format, args.extras
399
494
  end
400
495
  end
401
496
  when 'rebase'
402
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
403
504
  when :onto
404
- format_desc action, flag, 'commit,upstream,branch?=HEAD'
505
+ format_desc action, flag, 'branch/commit,upstream,branch?=HEAD'
405
506
  task flag, [:commit, :upstream, :branch] do |_, args|
406
507
  commit = param_guard(action, flag, args: args, key: :commit)
407
508
  upstream = param_guard(action, flag, args: args, key: :upstream)
408
509
  rebase(flag, commit: commit, upstream: upstream, branch: args.branch)
409
510
  end
410
- when :root
411
- format_desc action, flag, 'branch,onto?'
412
- task flag, [:branch, :onto] do |_, args|
413
- branch = param_guard(action, flag, args: args, key: :branch)
414
- rebase(flag, commit: args.onto, branch: branch)
415
- end
416
511
  when :send
417
- format_desc(action, flag, OPT_REBASE, arg: nil)
512
+ format_desc(action, flag, VAL_GIT[:rebase][:send], arg: nil)
418
513
  task flag, [:command] do |_, args|
419
514
  command = param_guard(action, flag, args: args, key: :command)
420
515
  rebase(flag, command: command)
421
516
  end
422
517
  end
423
518
  when 'rev'
424
- format_desc(action, flag, "ref?=HEAD#{flag == :commit ? ',size?' : ''}")
425
- task flag, [:ref, :size] do |_, args|
426
- 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
427
541
  end
428
542
  when 'refs', 'files'
429
- format_desc action, flag, 'grep?=pattern'
430
- task flag, [:grep] do |_, args|
431
- __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
432
554
  end
433
555
  end
434
556
  end
@@ -442,21 +564,18 @@ module Squared
442
564
  super
443
565
  end
444
566
 
445
- 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)
446
568
  cmd = git_session 'pull'
447
- if flag == :rebase
448
- cmd << '--rebase'
449
- cmd << '--autostash' if option('autostash')
450
- elsif (val = option('rebase', ignore: false))
569
+ if (val = option('rebase', ignore: false))
451
570
  cmd << case val
452
571
  when '0'
453
572
  '--no-rebase'
454
573
  else
455
- VAL_REBASE.include?(val) ? basic_option('rebase', val) : '--rebase'
574
+ VAL_GIT[:rebase][:value].include?(val) ? basic_option('rebase', val) : '--rebase'
456
575
  end
457
576
  end
458
- append_pull(opts, OPT_PULL + OPT_FETCH - (FOR_FETCH + FNO_FETCH), NO_PULL + NO_FETCH, remote: remote,
459
- 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)
460
579
  source(sync: sync, sub: if verbose
461
580
  [
462
581
  { pat: /^(.+)(\|\s+\d+\s+)([^-]*)(-+)(.*)$/, styles: :red, index: 4 },
@@ -465,39 +584,44 @@ module Squared
465
584
  end, **threadargs)
466
585
  end
467
586
 
468
- def rebase(flag = nil, sync: invoked_sync?('rebase', flag), command: nil, commit: nil, upstream: nil,
469
- branch: nil)
587
+ def rebase(flag = nil, opts = [], sync: invoked_sync?('rebase', flag), commit: nil, upstream: nil, branch: nil,
588
+ command: nil)
470
589
  return pull(:rebase, sync: sync) unless flag
471
590
 
472
591
  cmd = git_session 'rebase'
473
- cmd << '--interactive' unless flag == :send || !option('interactive', 'i')
474
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
475
604
  when :onto
476
605
  return unless upstream
477
606
 
478
- cmd << shell_option('onto', commit)
607
+ cmd << '--interactive' if option('interactive', 'i')
608
+ cmd << shell_option('onto', commit) if commit
479
609
  cmd << shell_escape(upstream)
480
610
  append_head branch
481
- when :root
482
- return unless branch
483
-
484
- cmd << shell_option('onto', commit) if commit
485
- cmd << '--root' << shell_escape(branch)
486
- when :send
487
- return unless OPT_REBASE.include?(command)
611
+ else
612
+ return unless VAL_GIT[:rebase][:send].include?(command)
488
613
 
489
614
  cmd << "--#{command}"
490
- else
491
- return
492
615
  end
493
616
  source
494
617
  end
495
618
 
496
- 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)
497
620
  cmd = git_session 'fetch'
498
621
  cmd << '--all' if !remote && !opts.include?('multiple') && option('all')
499
622
  cmd << '--verbose' if verbose && !opts.include?('quiet')
500
- 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)
501
625
  source(sync: sync, **threadargs)
502
626
  end
503
627
 
@@ -518,36 +642,39 @@ module Squared
518
642
  opts[:local] = val != '0' if (val = option('local', strict: true))
519
643
  opts.delete(:'recurse-submodules') || opts.delete(:'no-recurse-submodules') if append_submodules(:clone)
520
644
  append_hash opts
521
- if cmd.include?('--quiet') || cmd.include?('-q')
522
- quiet = true
523
- elsif verbose
524
- quiet = false
525
- else
526
- cmd << '--quiet'
527
- quiet = true
528
- end
529
- append_value([data[0], path], delim: true, escape: false)
530
- 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?)
531
648
  end
532
649
 
533
- def stash(flag = nil, files = [], sync: invoked_sync?('stash', flag), commit: nil)
534
- cmd = git_session 'stash', flag || 'push'
535
- case flag
536
- when :apply, :pop
537
- cmd << '--index' if option('index')
538
- 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
539
668
  else
540
- 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)
541
671
  append_message option('message', 'm', ignore: false)
542
- append_pathspec files
543
672
  end
544
- source(sync: sync, **threadargs)
673
+ source(banner: !quiet?, sync: sync, **threadargs)
545
674
  end
546
675
 
547
676
  def status(*, sync: invoked_sync?('status'), **)
548
- cmd = git_session 'status'
549
- cmd << (option('long') ? '--long' : '--short')
550
- cmd << '--branch' if option('branch')
677
+ cmd = git_session 'status', option('long') ? '--long' : '--short'
551
678
  if (val = option('ignore-submodules', ignore: false))
552
679
  cmd << basic_option('ignore-submodules', case val
553
680
  when '0', 'none'
@@ -568,8 +695,8 @@ module Squared
568
695
  end
569
696
  ret = write_lines(out, banner: banner, sub: if verbose
570
697
  [
571
- { pat: /^(.)([A-Z?!])(.+)$/, styles: :red, index: 2 },
572
- { pat: /^([A-Z?!])(.+)$/, styles: :green },
698
+ { pat: /^(.)([A-Z])(.+)$/, styles: :red, index: 2 },
699
+ { pat: /^([A-Z])(.+)$/, styles: :green },
573
700
  { pat: /^(\?\?)(.+)$/, styles: :red },
574
701
  { pat: /^(## )(.+)(\.{3})(.+)$/,
575
702
  styles: [nil, :green, nil, :red], index: -1 }
@@ -578,34 +705,41 @@ module Squared
578
705
  list_result(ret, 'files', from: from, action: 'modified')
579
706
  end
580
707
 
581
- def reset(flag, files = nil, mode: nil, ref: nil)
708
+ def reset(flag, opts = [], refs: nil, ref: nil, mode: nil, commit: nil)
582
709
  cmd = git_session 'reset'
583
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
584
720
  when :mode
585
- case mode
586
- when 'mixed'
587
- cmd << '--mixed'
721
+ return unless VAL_GIT[:reset].include?(mode)
722
+
723
+ cmd << "--#{mode}"
724
+ if mode == 'mixed'
588
725
  cmd << '-N' if option('n')
589
726
  cmd << '--no-refresh' if option('refresh', equals: '0')
590
- when 'soft', 'hard', 'merge', 'keep'
591
- cmd << "--#{mode}"
592
- when 'submodules'
593
- cmd << '--recurse-submodules'
594
- when 'no-submodules'
595
- cmd << '--no-recurse-submodules'
596
- else
597
- return
598
727
  end
599
728
  when :patch
600
729
  cmd << '--patch'
730
+ else
731
+ return
732
+ end
733
+ unless ref == false
734
+ append_commit ref
735
+ append_pathspec refs if refs
601
736
  end
602
- append_commit ref
603
- append_pathspec files if files
604
737
  source
605
738
  end
606
739
 
607
- 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)
608
741
  cmd = git_session 'checkout'
742
+ append_option 'force', 'merge'
609
743
  case flag
610
744
  when :branch
611
745
  cmd << '--detach' if detach == 'd' || option('detach')
@@ -628,92 +762,122 @@ module Squared
628
762
  end
629
763
  cmd << '--track' << origin
630
764
  when :detach
631
- cmd << "--#{flag}" << commit
765
+ cmd << '--detach' << commit
632
766
  else
633
- cmd << "--#{flag}"
634
- append_first %w[ours theirs]
635
- append_head
636
- 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
637
775
  end
638
776
  source
639
777
  end
640
778
 
641
- def tag(flag, refs, message: nil, commit: nil)
779
+ def tag(flag, opts = [], refs: [], message: nil, commit: nil)
642
780
  cmd = git_session 'tag'
643
781
  case flag
644
782
  when :add
645
783
  if option('sign')
646
784
  cmd << '--sign'
647
- else
648
- out = cmd.to_s
649
- 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'
650
787
  end
651
788
  if !commit && message && (hash = commithash(message))
652
789
  commit = hash
653
790
  else
654
791
  append_message message
655
792
  end
656
- append_value(refs, escape: false)
793
+ append_value refs
657
794
  append_head commit
658
- 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
659
807
  cmd << shell_option(flag, commit)
660
- append_option(%w[contains sort] + (flag == :list ? ['merged'] : []), equals: true) unless flag == :delete
661
- append_value(refs, escape: false)
662
808
  end
663
809
  source
664
810
  end
665
811
 
666
- 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: [])
667
830
  cmd = git_session 'diff'
668
- sha = []
831
+ files = option_sanitize(opts, collect_hash(OPT_GIT[:diff]) + OPT_GIT[:log][:diff],
832
+ no: OPT_GIT[:no][:log][:diff]).first
669
833
  case flag
670
- when :files, :between, :contain
834
+ when :files, :view, :between, :contain
671
835
  cmd.delete('--cached')
672
836
  else
673
837
  items = files.dup
838
+ sha = nil
674
839
  files.clear
675
840
  items.each do |val|
676
- if (hash = commithash(val))
677
- sha << hash
841
+ if (s = commithash(val))
842
+ (sha ||= []).push(s)
678
843
  else
679
844
  files << val
680
845
  end
681
846
  end
682
847
  end
683
- if (val = option('unified')).to_i > 0
684
- cmd << basic_option('unified', val)
685
- end
686
848
  append_nocolor
687
- case flag
688
- when :cached
689
- cmd << '--cached'
690
- cmd << '--merge-base' if option('merge-base')
691
- when :branch
692
- cmd << branch
693
- when :files
849
+ if flag == :files
694
850
  cmd << '--no-index'
695
- when :between, :contain
696
- cmd << shell_quote(range.join(flag == :between ? '..' : '...'))
851
+ append_pathspec(refs, parent: true)
697
852
  else
698
- if (val = option('index')) || index > 0
699
- cmd << "HEAD~#{val || index}"
700
- elsif !sha.empty? && option('merge-base')
701
- cmd << '--merge-base'
702
- end
703
- end
704
- unless sha.empty?
705
- if cmd.include?('--cached')
706
- raise_error('diff', sha.join(', '), hint: 'one commit') if sha.size > 1
707
- 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 ? '..' : '...'))
708
860
  else
709
- 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
710
874
  end
875
+ append_pathspec files
711
876
  end
712
- append_pathspec(files, parent: flag == :files)
713
- source(exception: cmd.include?('--exit-code'))
877
+ source(exception: session_arg?('exit-code'))
714
878
  end
715
879
 
716
- def commit(flag, files = [], message: nil, pass: false)
880
+ def commit(flag, *, refs: [], message: nil, pass: false)
717
881
  message ||= option('message', 'm', prefix: 'git', ignore: false)
718
882
  amend = flag.to_s.start_with?('amend')
719
883
  if !message && !amend
@@ -721,45 +885,59 @@ module Squared
721
885
 
722
886
  raise_error('commit', 'GIT_MESSAGE="description"', hint: 'missing')
723
887
  end
724
- pathspec = if flag == :all || (amend && files.size == 1 && files.first == '*')
888
+ pathspec = if flag == :all || (amend && refs.size == 1 && refs.first == '*')
725
889
  '--all'
890
+ elsif (refs = projectmap(refs)).empty?
891
+ raise_error('commit', 'pathspec', hint: 'missing')
726
892
  else
727
- raise_error('commit', 'pathspec', hint: 'missing') if (files = projectmap(files)).empty?
728
- "-- #{files.join(' ')}"
893
+ "-- #{refs.join(' ')}"
729
894
  end
730
- format = '%(if)%(HEAD)%(then)%(refname:short)...%(upstream:short)...%(upstream:track)%(end)'
731
- branch = nil
732
895
  origin = nil
733
- source(git_output('fetch --no-tags --quiet'), io: true, banner: false, stdout: true)
734
- cmd = git_output("for-each-ref --format=\"#{format}\" refs/heads")
735
- source(cmd, io: true, banner: false).first.each do |line|
736
- next if (line = line.chomp).empty?
737
-
738
- branch, origin, hint = line.split('...')
739
- if hint && !hint.match?(/^\[(\D+0,\D+0)\]$/)
740
- raise_error('work tree is not usable', hint: hint[1..-2])
741
- elsif origin.empty?
742
- return nil if pass
743
-
744
- 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
745
918
  end
746
919
  break
747
920
  end
748
- i = origin.index('/')
749
- branch = "#{branch}:#{origin[i + 1..-1]}" unless origin.end_with?("/#{branch}")
750
- origin = origin[0..i - 1]
921
+ raise_error('commit', 'work tree is not usable') unless origin && branch
751
922
  cmd = git_session('commit', option('dry-run') && '--dry-run', options: false)
752
- cmd << '--amend' if amend
923
+ if amend
924
+ cmd << '--amend'
925
+ else
926
+ cmd.delete('--amend')
927
+ end
753
928
  if message
754
929
  append_message message
755
930
  elsif flag == :'amend-orig' || option('no-edit')
756
931
  cmd << '--no-edit'
757
932
  end
758
933
  a = git_output 'add', '--verbose'
759
- b = git_output 'push'
760
- 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
761
939
  a << pathspec
762
- b << '--force-with-lease' if amend
940
+ b << '--force' if amend
763
941
  b << origin << branch
764
942
  puts if pass
765
943
  source a
@@ -767,7 +945,7 @@ module Squared
767
945
  source b
768
946
  end
769
947
 
770
- def branch(flag, names = [], target: nil, ref: nil, opts: [])
948
+ def branch(flag, opts = [], refs: [], ref: nil, target: nil)
771
949
  cmd = git_session 'branch'
772
950
  stdout = false
773
951
  case flag
@@ -784,8 +962,10 @@ module Squared
784
962
  end
785
963
  cmd << '--force' if option('force')
786
964
  when :set
787
- if ref.start_with?('!')
788
- 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])
789
969
  target = nil
790
970
  stdout = true
791
971
  else
@@ -793,9 +973,9 @@ module Squared
793
973
  end
794
974
  ref = nil
795
975
  when :delete
796
- force, list = names.partition { |val| val =~ /^[\^~]/ }
976
+ force, list = refs.partition { |val| val =~ /^[\^~]/ }
797
977
  force.each do |val|
798
- dr = val[0..2]
978
+ dr = val[0, 3]
799
979
  d = dr.include?('^') ? '-D' : '-d'
800
980
  r = dr.include?('~') ? '-r' : nil
801
981
  source git_output('branch', d, r, shell_quote(val.sub(/^[\^~]+/, '')))
@@ -807,27 +987,18 @@ module Squared
807
987
  when :move, :copy
808
988
  flag = "-#{flag.to_s[0]}"
809
989
  cmd << (option('force') ? flag.upcase : flag)
810
- names.compact.each { |val| cmd << shell_quote(val) }
990
+ refs.compact.each { |val| cmd << shell_quote(val) }
811
991
  stdout = true
812
992
  when :edit
813
993
  cmd << '--edit-description'
814
994
  when :current
815
995
  cmd << '--show-current'
816
996
  else
817
- opts, pat = option_partition(opts, OPT_BRANCH, no: NO_BRANCH)
997
+ opts = option_sanitize(opts, OPT_GIT[:branch], no: OPT_GIT[:no][:branch]).first
818
998
  grep = []
819
999
  opts.each do |opt|
820
1000
  if opt =~ /^(v+)$/
821
1001
  cmd << "-#{$1}"
822
- elsif opt =~ pat
823
- case $1
824
- when 'column', 'format'
825
- cmd << quote_option($1, $2)
826
- when 'abbrev'
827
- cmd << basic_option($1, $2) if $2.to_i > 0
828
- else
829
- cmd << shell_option($1, $2)
830
- end
831
1002
  else
832
1003
  grep << opt
833
1004
  end
@@ -848,16 +1019,24 @@ module Squared
848
1019
  source(stdout: stdout)
849
1020
  end
850
1021
 
851
- def restore(flag, files, tree: nil)
852
- source = flag == :source
853
- cmd = git_session 'restore', source && files.empty? ? '--patch' : nil, shell_option(flag, tree)
854
- append_option %w[staged worktree]
855
- append_first %w[ours theirs]
856
- append_pathspec(files, expect: !cmd.include?('--patch'))
857
- 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)
858
1037
  end
859
1038
 
860
- def show(objs, format: nil, opts: nil)
1039
+ def show(format, opts = [])
861
1040
  cmd = git_session 'show'
862
1041
  if format
863
1042
  case (val = format.downcase)
@@ -867,41 +1046,54 @@ module Squared
867
1046
  if format =~ /^t?format:/ || format.include?('%')
868
1047
  cmd << quote_option('pretty', format)
869
1048
  else
870
- objs << format
1049
+ opts << format
871
1050
  end
872
1051
  end
873
1052
  end
874
- if opts
875
- append_hash opts
876
- banner = format != 'oneline'
877
- 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')
878
1056
  cmd << basic_option('abbrev', val) if (val = option('abbrev')) && val.to_i > 0
879
1057
  banner = true
880
1058
  end
881
- append_value(objs, delim: true)
1059
+ append_value(refs, delim: true)
882
1060
  source(exception: false, banner: banner)
883
1061
  end
884
1062
 
885
- def rev_parse(flag, ref: nil, size: nil)
886
- git_session 'rev-parse', if flag == :branch
887
- '--abbrev-ref'
888
- else
889
- (n = size.to_i) > 0 ? basic_option('short', [n, 5].max) : '--verify'
890
- end
891
- append_commit ref
892
- 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)
893
1081
  end
894
1082
 
895
- def ls_remote(flag, grep: nil)
896
- 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
897
1088
  out, banner, from = source(io: true)
898
1089
  print_item banner
899
1090
  ret = write_lines(out, grep: grep)
900
1091
  list_result(ret, flag.to_s, from: from, grep: grep)
901
1092
  end
902
1093
 
903
- def ls_files(flag, grep: nil)
1094
+ def ls_files(flag, opts = [])
904
1095
  git_session 'ls-files', "--#{flag}"
1096
+ grep = option_sanitize(opts, OPT_GIT[:ls_files]).first
905
1097
  out, banner, from = source(io: true)
906
1098
  print_item banner
907
1099
  ret = write_lines(out, grep: grep)
@@ -928,8 +1120,8 @@ module Squared
928
1120
  banner &&= cmd.temp { |val| val.start_with?('--work-tree') || val.start_with?('--git-dir') }
929
1121
  end
930
1122
  cmd = session_done(cmd)
931
- log&.info cmd
932
- on :first, from if from
1123
+ log.info cmd
1124
+ on :first, from
933
1125
  banner = if banner
934
1126
  format_banner((banner.is_a?(String) ? banner : cmd).gsub(File.join(path, ''), ''), banner: true)
935
1127
  end
@@ -964,26 +1156,32 @@ module Squared
964
1156
  end
965
1157
  end
966
1158
  rescue StandardError => e
967
- log&.error e
968
- ret = on(:error, from, e) if from
1159
+ log.error e
1160
+ ret = on(:error, from, e)
969
1161
  raise if exception && ret != true
970
1162
 
971
1163
  warn log_message(Logger::WARN, e) if warning?
972
1164
  else
973
- on :last, from if from
1165
+ on :last, from
974
1166
  end
975
1167
  end
976
1168
 
977
1169
  def write_lines(data, banner: nil, loglevel: nil, grep: nil, sub: nil, pass: false)
978
- 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
979
1177
  sub = nil if stdin?
980
1178
  ret = 0
981
1179
  out = []
982
1180
  data.each do |line|
983
- next if grep && !line.match?(grep)
1181
+ next if grep&.none? { |pat| pat.match?(line) }
984
1182
 
985
1183
  if loglevel
986
- log&.add loglevel, line
1184
+ log.add loglevel, line
987
1185
  else
988
1186
  sub&.each { |h| line = sub_style(line, **h) }
989
1187
  if banner
@@ -1003,38 +1201,37 @@ module Squared
1003
1201
  if size > 0
1004
1202
  styles = theme.fetch(:banner, []).reject { |s| s.to_s.end_with?('!') }
1005
1203
  styles << :bold if styles.size <= 1
1006
- 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}",
1007
1205
  sub: { pat: /\A(\d+)(.+)\z/, styles: styles })
1008
1206
  else
1009
- 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)
1010
1213
  end
1011
1214
  end
1012
- on :last, from if from
1215
+ on :last, from
1013
1216
  end
1014
1217
 
1015
- def append_pull(opts, list, no = [], target: @session, flag: nil, remote: nil)
1016
- target << '--force' if option('force', target: target)
1017
- 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)
1018
1221
  out = []
1019
1222
  refspec = []
1020
- 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)
1021
1224
  opts.each do |opt|
1022
1225
  if opt =~ pat
1023
1226
  case $1
1024
1227
  when 'rebase'
1025
- target << basic_option($1, $2) if VAL_REBASE.include?($2)
1228
+ target << basic_option($1, $2) if VAL_GIT[:rebase][:value].include?($2)
1026
1229
  when 'shallow-since'
1027
1230
  next unless (val = Date.parse($2))
1028
1231
 
1029
1232
  target << quote_option($1, val.strftime('%F %T'))
1030
1233
  when 'recurse-submodules'
1031
- target << basic_option($1, $2) unless modules
1032
- when 'shallow-exclude', 'gpg-sign', 'signoff', 'strategy', 'strategy-option'
1033
- target << shell_option($1, $2)
1034
- when 'refmap', 'negotiation-tip'
1035
- target << quote_option($1, $2)
1036
- when 'depth', 'deepen', 'log', 'jobs'
1037
- target << basic_option($1, $2) if $2.to_i > 0
1234
+ target << basic_option($1, $2) unless rsm
1038
1235
  when 'refspec'
1039
1236
  refspec << shell_escape($2, quote: true)
1040
1237
  end
@@ -1043,9 +1240,9 @@ module Squared
1043
1240
  end
1044
1241
  end
1045
1242
  if remote
1046
- append_value(remote, target: target, delim: true, quote: true)
1047
- if (val = option('refspec', target: target, strict: true))
1048
- 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)
1049
1246
  else
1050
1247
  target.merge(refspec)
1051
1248
  end
@@ -1063,47 +1260,45 @@ module Squared
1063
1260
  end
1064
1261
 
1065
1262
  def append_pathspec(files = [], target: @session, expect: false, parent: false)
1066
- if files.empty? && (val = option('pathspec', target: target))
1067
- files = split_escape(val)
1068
- end
1069
- files = projectmap(files, parent: parent)
1070
- if !files.empty?
1071
- target << "-- #{files.join(' ')}"
1072
- elsif expect
1073
- 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
1074
1275
  end
1075
1276
  end
1076
1277
 
1077
1278
  def append_message(val, target: @session)
1078
- target << "--message=\"#{double_quote(val)}\"" unless val.to_s.empty?
1279
+ target << quote_option('message', val) unless val.to_s.empty?
1079
1280
  end
1080
1281
 
1081
1282
  def append_head(val = nil, target: @session)
1082
1283
  return target << val if val
1083
1284
 
1084
- 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)
1085
1286
  end
1086
1287
 
1087
1288
  def append_submodules(from = nil, target: @session)
1088
- return unless (val = option('recurse-submodules', target: target, ignore: false))
1289
+ return unless (val = option('recurse-submodules', ignore: false))
1089
1290
 
1090
1291
  if from == :clone
1091
- case val
1092
- when '0', 'false'
1093
- target << '--no-recurse-submodules'
1094
- when '1', 'true'
1095
- target << '--recurse-submodules'
1096
- else
1097
- projectmap(split_escape(val)).each do |path|
1098
- target << basic_option('recurse-submodules', path)
1099
- end
1292
+ projectmap(split_escape(val)).each do |path|
1293
+ target << basic_option('recurse-submodules', path)
1100
1294
  end
1295
+ target
1101
1296
  else
1102
1297
  target << case val
1103
1298
  when 'no', '0'
1104
1299
  '--no-recurse-submodules'
1105
1300
  when 'yes', 'on-demand'
1106
- "--recurse-submodules=#{val}"
1301
+ "--recurse-submodules#{from == :reset ? '' : "=#{val}"}"
1107
1302
  else
1108
1303
  '--recurse-submodules'
1109
1304
  end
@@ -1119,8 +1314,14 @@ module Squared
1119
1314
  git_session(*cmd, main: false, options: false, **kwargs)
1120
1315
  end
1121
1316
 
1122
- def dryrun?(*)
1123
- !!@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')
1124
1325
  end
1125
1326
 
1126
1327
  def gitpath
@@ -1128,7 +1329,7 @@ module Squared
1128
1329
  end
1129
1330
 
1130
1331
  def commithash(val)
1131
- (data = /\A#\{(\h{5,40})\}\z/.match(val)) ? data[1] : nil
1332
+ val =~ /\A#\{(\h{5,40})\}\z/ ? $1 : nil
1132
1333
  end
1133
1334
 
1134
1335
  def threadargs