squared 0.8.2 → 0.8.4

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.
@@ -143,7 +143,6 @@ module Squared
143
143
  end
144
144
  File.write(@revfile, JSON.pretty_generate(@revdoc))
145
145
  rescue => e
146
- log&.debug e
147
146
  warn log_warn(e, pass: true) if warning
148
147
  ensure
149
148
  @revlock = false
@@ -165,6 +164,16 @@ module Squared
165
164
  sort=q t|track=b].freeze,
166
165
  checkout: %w[l d|detach f|force ignore-other-worktrees ignore-skip-worktree-bits m|merge p|patch
167
166
  pathspec-file-nul q|quiet ours theirs conflict=b orphan=b pathspec-from-file=p t|track=b].freeze,
167
+ clone: %w[also-filter-submodules bare dissociate l|local mirror no-hardlinks n|no-checkout no-tags o|origin=b
168
+ progress q|quiet s|shared sparse v|verbose b|branch=b bundle-uri=q c|config=q depth=i filter=q
169
+ j|jobs=i reference=q reference-if-able=q o|origin=b recurse-submodules=p? ref-format=b
170
+ separate-git-dir=p server-option=q shallow-exclude=b shallow-since=v template=p
171
+ u|upload-pack=q].freeze,
172
+ commit: %w[e n s S=bm? u=bm? a|all allow-empty allow-empty-message amend branch dry-run i|include long
173
+ no-post-rewrite o|only pathspec-file-nul z|null p|patch porcelain q|quiet reset-author short
174
+ v|verbose trailer=q author=q cleanup=b date=q fixup=b f|file=p gpg-sign=b c|reedit-message=b
175
+ C|reuse-message=b m|message=q pathspec-from-file=p squash=b t|template=p
176
+ untracked-files=b?].freeze,
168
177
  diff: {
169
178
  base: %w[0 1|base 2|ours 3|theirs cached merge-base].freeze,
170
179
  show: %w[s exit-code histogram].freeze
@@ -172,9 +181,10 @@ module Squared
172
181
  fetch: {
173
182
  base: %w[multiple porcelain progress P|prune-tags refetch stdin u|update-head-ok
174
183
  recurse-submodules-default=b?].freeze,
175
- pull: %w[4 6 n t a|append atomic dry-run f|force k|keep negotiate-only prefetch p|prune q|quiet set-upstream
176
- unshallow update-shallow v|verbose deepen=i depth=i j|jobs=i negotiation-tip=q recurse-submodules=v
177
- refmap=q o|server-option=q shallow-exclude=b shallow-since=v upload-pack=q].freeze
184
+ pull: %w[n t 4|ipv4 6|ipv6 a|append atomic dry-run f|force k|keep negotiate-only prefetch p|prune q|quiet
185
+ set-upstream unshallow update-shallow v|verbose deepen=i depth=i j|jobs=i negotiation-tip=q
186
+ recurse-submodules=v refmap=q o|server-option=q shallow-exclude=b shallow-since=v
187
+ upload-pack=q].freeze
178
188
  }.freeze,
179
189
  git: {
180
190
  add: %w[N|intent-to-add].freeze,
@@ -215,7 +225,7 @@ module Squared
215
225
  graph ita-invisible-in-index minimal name-only name-status no-color-moved-ws no-prefix no-renames
216
226
  numstat patch-with-raw patch-with-stat patience pickaxe-all pickaxe-regex raw shortstat summary
217
227
  a|text abbrev=i? anchored=q break-rewrites=b? color=b color-moved=b color-moved-ws=b color-words=q?
218
- diff-algorithm=b diff-filter=e? X|dirstat=b? dirstat-by-file=b? dst-prefix=q find-copies=i?
228
+ diff-algorithm=b diff-filter=q? X|dirstat=b? dirstat-by-file=b? dst-prefix=q find-copies=i?
219
229
  find-object=b find-renames=b? ignore-matching-lines=q ignore-submodules=b? line-prefix=q
220
230
  max-depth=n output=p output-indicator-context=q output-indicator-new=q output-indicator-old=q
221
231
  relative=p rotate-to=p skip-to=p src-prefix=q stat=b? stat-count=i stat-width=i stat-name-width=i
@@ -230,6 +240,9 @@ module Squared
230
240
  gpg-sign=b? into-name=b log=i s|strategy=b X|strategy-option=b].freeze,
231
241
  pull: %w[e n S=bm? allow-unrelated-histories compact-summary ff-only cleanup=b gpg-sign=b? log=i r|rebase=v?
232
242
  s|strategy=b X|strategy-option=b].freeze,
243
+ push: %w[4|ipv4 6|ipv6 d|delete f|force n|dry-run follow-tags mirror no-recurse-submodules porcelain progress
244
+ prune q|quiet u|set-upstream tags v|verbose exec=q force-with-lease=b o|push-option=q receive-pack=q
245
+ recurse-submodules=b repo=q signed=b].freeze,
233
246
  range_diff: %w[left-only no-dual-color no-notes remerge-diff right-only creation-factor=i diff-merges=b
234
247
  notes=q?].freeze,
235
248
  rebase: %w[n C=im S=bm? allow-empty-message apply committer-date-is-author-date edit-todo empty=b
@@ -288,9 +301,11 @@ module Squared
288
301
  blame: %w[progress].freeze,
289
302
  branch: %w[color color-moved column track].freeze,
290
303
  checkout: %w[overwrite-ignore guess overlay progress recurse-submodules track].freeze,
304
+ clone: %w[reject-shallow remote-submodules single-branch shallow-submodules].freeze,
305
+ commit: %w[edit gpg-sign signoff status verify].freeze,
291
306
  fetch: {
292
307
  base: %w[auto-gc auto-maintenance write-commit-graph write-fetch-head].freeze,
293
- pull: %w[all ipv4 ipv6 recurse-submodules show-forced-updates tags].freeze
308
+ pull: %w[all recurse-submodules show-forced-updates tags].freeze
294
309
  },
295
310
  grep: %w[color exclude-standard recursive textconv].freeze,
296
311
  log: {
@@ -301,6 +316,7 @@ module Squared
301
316
  merge: %w[autostash edit ff gpg-sign log overwrite-ignore progress rerere-autoupdate signoff squash stat
302
317
  verify verify-signatures].freeze,
303
318
  pull: %w[autostash commit edit gpg-sign ff log rebase signoff squash stat verify verify-signatures].freeze,
319
+ push: %w[atomic force-if-includes force-with-lease signed thin verify].freeze,
304
320
  rebase: %w[autosquash autostash fork-point gpg-sign keep-empty reapply-cherry-picks rebase-merges
305
321
  rerere-autoupdate reschedule-failed-exec stat update-refs verify].freeze,
306
322
  reset: %w[refresh].freeze,
@@ -323,7 +339,7 @@ module Squared
323
339
  }.freeze,
324
340
  rebase: {
325
341
  send: %w[continue skip abort quit].freeze,
326
- value: %w[true false merges interactive].freeze
342
+ value: %w[false true merges interactive].freeze
327
343
  }.freeze,
328
344
  reset: %w[soft mixed hard merge keep recurse-submodules no-recurse-submodules].freeze,
329
345
  revbuild: %w[untracked-files ignore-submodules ignored].freeze
@@ -347,7 +363,8 @@ module Squared
347
363
  subtasks({
348
364
  'branch' => %i[create track delete move copy list all current].freeze,
349
365
  'checkout' => %i[commit branch track detach path].freeze,
350
- 'commit' => %i[add all amend amend-orig fixup].freeze,
366
+ 'commit' => %i[head add all amend amend-orig fixup].freeze,
367
+ 'clone' => %i[branch tag].freeze,
351
368
  'diff' => %i[head branch files view between contain].freeze,
352
369
  'range-diff' => %i[view between contain].freeze,
353
370
  'fetch' => %i[origin remote all].freeze,
@@ -356,6 +373,7 @@ module Squared
356
373
  'log' => %i[grep view between contain].freeze,
357
374
  'merge' => %i[commit no-commit send].freeze,
358
375
  'pull' => %i[origin remote all].freeze,
376
+ 'push' => %i[origin remote commit all tags].freeze,
359
377
  'rebase' => %i[branch onto send].freeze,
360
378
  'refs' => %i[heads tags remote].freeze,
361
379
  'remote' => %i[add select].freeze,
@@ -395,7 +413,8 @@ module Squared
395
413
  if flag == :remote
396
414
  format_desc action, flag, 'remote?,opts*'
397
415
  task flag, [:remote] do |_, args|
398
- args = if (remote = args.remote)
416
+ remote = args.remote
417
+ args = if remote && !git_grep('remote', remote).empty?
399
418
  args.extras
400
419
  else
401
420
  remote = choice_remote
@@ -409,6 +428,46 @@ module Squared
409
428
  __send__ action, flag, args.to_a
410
429
  end
411
430
  end
431
+ when 'push'
432
+ case flag
433
+ when :origin, :remote
434
+ format_desc(action, flag, 'branch/::,opts*', before: ('origin/:' if flag == :remote))
435
+ task flag, (flag == :remote ? %i[origin branch] : %i[branch]) do |_, args|
436
+ if flag == :remote
437
+ origin = param_guard(action, flag, args: args, key: :origin)
438
+ origin = choice_remote(force: true) if origin == ':' || !git_grep('remote', origin).empty?
439
+ else
440
+ origin = remotetrack
441
+ end
442
+ branch = param_guard(action, flag, args: args, key: :branch)
443
+ if branch == '::'
444
+ branch = choice_refs('Choose a branch', 'heads', series: true, accept: 'Push?')
445
+ end
446
+ push(flag, args.extras, origin: origin, branch: branch)
447
+ end
448
+ when :commit
449
+ format_desc action, flag, 'commit?|:,opts*'
450
+ task flag, [:commit] do |_, args|
451
+ ref = args.commit
452
+ if !ref || ref == ':'
453
+ ref = choice_commit(range: '@{u}..',
454
+ empty: log_message('No pending commits', hint: remotetrack))
455
+ end
456
+ push(flag, args.extras, ref: ref)
457
+ end
458
+ else
459
+ format_desc(action, flag, 'origin?,opts*', after: ('refs*' unless flag == :all))
460
+ task flag, [:origin] do |_, args|
461
+ origin = args.origin
462
+ args = if origin && !git_grep('remote', origin).empty?
463
+ args.extras
464
+ else
465
+ origin = nil
466
+ args.to_a
467
+ end
468
+ push(flag, args, origin: origin)
469
+ end
470
+ end
412
471
  when 'submodule'
413
472
  break unless @submodule
414
473
 
@@ -435,10 +494,14 @@ module Squared
435
494
  end
436
495
  when 'commit'
437
496
  case flag
438
- when :all
439
- format_desc action, flag, 'message?'
497
+ when :head, :all
498
+ format_desc(action, flag, 'message?|:', after: ('opts*,pathspec*' if flag == :head))
440
499
  task flag, [:message] do |_, args|
441
- commit(flag, message: args.message)
500
+ message = args.message
501
+ if message == ':' || (!message && flag == :head)
502
+ message = readline('Enter message', force: true)
503
+ end
504
+ commit(flag, flag == :head ? args.extras : [], message: message)
442
505
  end
443
506
  else
444
507
  format_desc(action, flag, 'pathspec+', before: ('opts*' if flag == :add))
@@ -495,7 +558,8 @@ module Squared
495
558
  when :add, :sign
496
559
  format_desc action, flag, 'name,message?,commit?,remote?'
497
560
  task flag, [:name, :message, :commit, :remote] do |_, args|
498
- if (name = args.name)
561
+ name = args.name
562
+ if name
499
563
  message = args.message
500
564
  commit = commithead args.commit
501
565
  remote = args.remote
@@ -534,9 +598,10 @@ module Squared
534
598
  format_desc action, flag, '(^)commit*|:,opts*,pathspec*'
535
599
  task flag do |_, args|
536
600
  args = args.to_a
537
- if args.first == ':'
538
- args.shift
539
- index = choice_commit(multiple: true)
601
+ if choice!(args, empty: true)
602
+ index = choice_commit('Choose revision range', multiple: true, series: true)
603
+ exclude = choice_commit('With exclusions', multiple: true, force: false)
604
+ index.concat(exclude.map { |val| "^#{val}" }) if exclude
540
605
  else
541
606
  index = args.each_with_object([]) do |val, out|
542
607
  if matchhead(val)
@@ -553,33 +618,32 @@ module Squared
553
618
  end
554
619
  log_(flag, args, index: index)
555
620
  end
556
- next
557
- end
558
- format_desc action, flag, 'commit1,commit2,opts*,pathspec*'
559
- task flag, [:commit1, :commit2] do |_, args|
560
- commit1 = commithead args.commit1
561
- if commit1
562
- range = [commit1, commithead(param_guard(action, flag, args: args, key: :commit2))]
563
- opts = args.extras
564
- else
565
- range, opts, refs = choice_commit(multiple: flag == :view ? true : 2,
566
- values: %w[Options Pathspec])
567
- range.reverse!
568
- opts = OptionPartition.strip(opts)
569
- opts.concat(refs.shellsplit) if refs
570
- end
571
- if action == 'log'
572
- log_(flag, opts, range: range)
573
- else
574
- diff(flag, opts, range: range, from: action.to_sym)
621
+ else
622
+ format_desc action, flag, 'commit1,commit2,opts*,pathspec*'
623
+ task flag, [:commit1, :commit2] do |_, args|
624
+ commit1 = commithead args.commit1
625
+ if commit1
626
+ range = [commit1, commithead(param_guard(action, flag, args: args, key: :commit2))]
627
+ opts = args.extras
628
+ else
629
+ range, opts, refs = choice_commit(multiple: flag == :view ? true : 2,
630
+ values: %w[Options Pathspec])
631
+ range.reverse!
632
+ opts = OptionPartition.strip(opts)
633
+ opts.concat(refs.shellsplit) if refs
634
+ end
635
+ if action == 'log'
636
+ log_(flag, opts, range: range)
637
+ else
638
+ diff(flag, opts, range: range, from: action.to_sym)
639
+ end
575
640
  end
576
641
  end
577
642
  when :head
578
643
  format_desc action, flag, 'commit*|:,opts*,pathspec*'
579
644
  task flag do |_, args|
580
645
  args = args.to_a
581
- if args.first == ':'
582
- args.shift
646
+ if choice!(args, empty: true)
583
647
  index = choice_commit(multiple: true)
584
648
  else
585
649
  index = args.each_with_object([]) do |val, out|
@@ -621,10 +685,10 @@ module Squared
621
685
  when 'i', 'E', 'F', 'P'
622
686
  opts << last
623
687
  else
624
- if last =~ /^(f(-ormat)?)=(.+)$/
688
+ if last =~ /^f(?:-ormat)?=(.+)$/
625
689
  opts.shift
626
690
  opts << "format=#{$1}"
627
- elsif last =~ /^(max(-count)?)=(\d+)$/
691
+ elsif last =~ /^max(?:-count)?=(\d+)$/
628
692
  opts << "max-count=#{$1}"
629
693
  else
630
694
  grep << last
@@ -639,9 +703,10 @@ module Squared
639
703
  when 'checkout'
640
704
  case flag
641
705
  when :branch
642
- format_desc action, flag, 'name,create?=[bB],commit?,d/etach?'
643
- task flag, [:name, :create, :commit, :detach] do |_, args|
644
- if (branch = args.name)
706
+ format_desc action, flag, 'branch,create?=[bB],commit?,d/etach?'
707
+ task flag, [:branch, :create, :commit, :detach] do |_, args|
708
+ branch = args.branch
709
+ if branch
645
710
  create = args.create
646
711
  detach = if args.commit == 'd'
647
712
  commit = nil
@@ -665,20 +730,22 @@ module Squared
665
730
  checkout(flag, branch: branch, create: create, commit: commit, detach: detach)
666
731
  end
667
732
  when :track
668
- format_desc action, flag, 'origin,(^)name?'
669
- task flag, [:origin, :name] do |_, args|
670
- if (origin = args.origin)
733
+ format_desc action, flag, 'remote,(^)name?'
734
+ task flag, [:remote, :name] do |_, args|
735
+ origin = args.remote
736
+ if origin
671
737
  branch = args.name
672
738
  else
673
739
  origin, branch = choice_refs('Choose a remote', 'remotes', values: 'Enter branch name')
674
740
  end
675
- checkout(flag, branch: branch, origin: origin)
741
+ checkout(flag, origin: origin, branch: branch)
676
742
  end
677
743
  when :commit
678
- format_desc action, flag, 'ref,opts*'
744
+ format_desc action, flag, 'commit?|:,opts*'
679
745
  task flag, [:commit] do |_, args|
680
746
  commit = commithead args.commit
681
747
  args = if commit
748
+ commit = choice_commit if commit == ':'
682
749
  args.extras
683
750
  else
684
751
  commit, opts = choice_commit(values: 'Options')
@@ -687,7 +754,7 @@ module Squared
687
754
  checkout(flag, args, commit: commit)
688
755
  end
689
756
  when :detach
690
- format_desc action, flag, 'ref?'
757
+ format_desc action, flag, 'commit?'
691
758
  task flag, [:commit] do |_, args|
692
759
  commit = commithead args.commit
693
760
  unless commit
@@ -705,7 +772,7 @@ module Squared
705
772
  when 'branch'
706
773
  case flag
707
774
  when :create
708
- format_desc action, flag, 'name,ref/:'
775
+ format_desc action, flag, 'name,ref?|:'
709
776
  task flag, [:name, :ref] do |_, args|
710
777
  target = param_guard(action, flag, args: args, key: :name)
711
778
  ref = commithead args.ref
@@ -717,7 +784,8 @@ module Squared
717
784
  when :track
718
785
  format_desc action, flag, '(^~)upstream?,name?'
719
786
  task flag, [:upstream, :name] do |_, args|
720
- if (ref = args.upstream)
787
+ ref = args.upstream
788
+ if ref
721
789
  target = args.name
722
790
  remote = true if ref.delete_prefix!('~')
723
791
  else
@@ -730,12 +798,12 @@ module Squared
730
798
  format_desc action, flag, '[^~]name*,:?'
731
799
  task flag do |_, args|
732
800
  refs = args.to_a
733
- if refs.empty? || (i = refs.last == ':')
801
+ if refs.empty? || (ia = refs.last == ':')
734
802
  accept = ['Delete?']
735
- accept << accept_b('Force?') unless i
736
- remote = choice_refs('Choose a branch', i ? 'remotes' : 'heads', multiple: true,
737
- accept: accept)
738
- if i
803
+ accept << accept_b('Force?') unless ia
804
+ remote = choice_refs('Choose a branch', ia ? 'remotes' : 'heads', multiple: true,
805
+ accept: accept)
806
+ if ia
739
807
  refs.pop
740
808
  else
741
809
  refs = remote.first
@@ -753,7 +821,8 @@ module Squared
753
821
  when :move, :copy
754
822
  format_desc action, flag, 'branch,oldbranch?'
755
823
  task flag, [:branch, :oldbranch] do |_, args|
756
- if (branch = args.branch)
824
+ branch = args.branch
825
+ if branch
757
826
  oldbranch = args.oldbranch
758
827
  else
759
828
  oldbranch, branch = choice_refs("Choose a branch to #{flag}",
@@ -767,51 +836,57 @@ module Squared
767
836
  branch flag
768
837
  end
769
838
  end
839
+ when 'clone'
840
+ format_desc(action, flag, flag == :tag ? 'dir,tag/:' : 'dir,branch/:', after: 'opts*')
841
+ task flag, [:dir, :ref] do |_, args|
842
+ dir = param_guard(action, flag, args: args, key: :dir)
843
+ ref = args.ref
844
+ if !ref || ref == ':'
845
+ ref = flag == :tag ? choice_refs('Choose a tag', 'tags') : choice_refs('Choose a branch')
846
+ end
847
+ clone(flag, args.extras, dir: emptypath(dir, create: false), ref: ref)
848
+ end
770
849
  when 'switch'
771
850
  case flag
772
851
  when :create
773
- format_desc action, flag, '(^)name,ref/:'
774
- task flag, [:name, :commit] do |_, args|
775
- branch = param_guard(action, flag, args: args, key: :name)
852
+ format_desc action, flag, '(^)branch,commit?|:'
853
+ task flag, [:branch, :commit] do |_, args|
854
+ branch = param_guard(action, flag, args: args, key: :branch)
776
855
  commit = commithead args.commit
777
856
  commit, track = choice_commit(force: false, values: 'Track? [Y/n]') if commit == ':'
778
857
  switch(flag, branch: branch, commit: commit, track: track)
779
858
  end
780
859
  when :detach
781
- format_desc action, flag, 'ref?'
860
+ format_desc action, flag, 'commit?|:'
782
861
  task flag, [:commit] do |_, args|
783
- commit = commithead(args.commit) || choice_commit(force: false)
862
+ commit = commithead args.commit
863
+ commit = choice_commit(force: false) if commit == ':'
784
864
  switch(flag, commit: commit)
785
865
  end
786
866
  when :branch
787
- format_desc action, flag, 'name/:,opts*'
788
- task flag, [:name] do |_, args|
789
- args = if (branch = args.name)
790
- branch = nil if branch == ':'
791
- args.extras
792
- else
793
- []
794
- end
795
- switch(flag, args, branch: branch || choice_refs('Choose a branch'))
867
+ format_desc action, flag, 'branch/:,opts*'
868
+ task flag, [:branch] do |_, args|
869
+ branch = args.branch
870
+ branch = nil if branch == ':'
871
+ switch(flag, args.extras, branch: branch || choice_refs('Choose a branch'))
796
872
  end
797
873
  end
798
874
  when 'reset'
799
875
  case flag
800
876
  when :commit
801
- format_desc action, flag, 'ref/:,opts*'
877
+ format_desc action, flag, 'commit?|:,opts*'
802
878
  task flag, [:commit] do |_, args|
803
879
  commit = commithead args.commit
804
- args = if commit && commit != ':'
805
- args.extras
806
- else
807
- commit, mode = choice_commit(values: ['Mode [mixed|soft|hard|N]'])
808
- args.extras.concat(case mode&.downcase
809
- when 'h', 'hard' then ['hard']
810
- when 's', 'soft' then ['soft']
811
- when 'n', 'N' then %w[mixed N]
812
- else ['mixed']
813
- end)
814
- end
880
+ args = args.extras
881
+ if !commit || commit == ':'
882
+ commit, mode = choice_commit(values: ['Mode [mixed|soft|hard|N]'])
883
+ args.concat(case mode&.downcase
884
+ when 'h', 'hard' then ['hard']
885
+ when 's', 'soft' then ['soft']
886
+ when 'n', 'N' then %w[mixed N]
887
+ else ['mixed']
888
+ end)
889
+ end
815
890
  success?(reset(flag, args, commit: commit))
816
891
  end
817
892
  when :index
@@ -860,9 +935,11 @@ module Squared
860
935
  when 'rebase', 'merge'
861
936
  case flag
862
937
  when :branch
863
- format_desc action, flag, 'upstream,branch?,opts*'
938
+ format_desc action, flag, 'upstream?|:,opts*'
864
939
  task flag, [:upstream] do |_, args|
865
- args = if (upstream = args.upstream)
940
+ upstream = args.upstream
941
+ args = if upstream
942
+ upstream = choice_refs 'Choose upstream branch' if upstream == ':'
866
943
  args.extras
867
944
  else
868
945
  upstream, opts = choice_refs('Choose upstream branch', values: 'Options')
@@ -871,11 +948,12 @@ module Squared
871
948
  rebase(flag, args, upstream: upstream)
872
949
  end
873
950
  when :onto
874
- format_desc action, flag, 'ref,upstream,branch?'
951
+ format_desc action, flag, 'commit|:,upstream,branch?'
875
952
  task flag, [:commit, :upstream, :branch] do |_, args|
876
953
  commit = commithead args.commit
877
954
  args = if commit
878
955
  upstream = param_guard(action, flag, args: args, key: :upstream)
956
+ commit = choice_commit if commit == ':'
879
957
  branch = args.branch
880
958
  []
881
959
  else
@@ -889,8 +967,9 @@ module Squared
889
967
  when :commit, :'no-commit'
890
968
  format_desc action, flag, 'branch|:,ours|theirs?,opts*'
891
969
  task flag, [:branch] do |_, args|
892
- current = `#{git_output('branch --show-current')}`.chomp
893
- if (branch = args.branch)
970
+ branch = args.branch
971
+ current = git_spawn('branch --show-current').chomp
972
+ if branch
894
973
  branch = choice_refs('Choose a branch', accept: "#{action.capitalize}?") if branch == ':'
895
974
  opts = args.extras
896
975
  if has_value!(opts, 'ours')
@@ -903,9 +982,11 @@ module Squared
903
982
  accept: "Merge with #{current}?")
904
983
  opts = OptionPartition.strip(opts)
905
984
  end
906
- raise ArgumentError, 'nothing to merge' if current == branch
907
-
908
- merge(flag, opts, branch: branch)
985
+ if current == branch
986
+ puts log_message('nothing to merge', subject: name, hint: branch)
987
+ else
988
+ merge(flag, opts, branch: branch)
989
+ end
909
990
  end
910
991
  when :send
911
992
  format_desc(action, flag, VAL_GIT[action.to_sym][:send], arg: nil)
@@ -922,7 +1003,7 @@ module Squared
922
1003
  task flag, [:ref, :size] do |_, args|
923
1004
  ref = commithead args.ref
924
1005
  size = args.size
925
- if !size && ref.to_i.between?(1, 40)
1006
+ if !size && ref.to_i.between?(4, 40)
926
1007
  size = ref
927
1008
  ref = nil
928
1009
  end
@@ -949,9 +1030,17 @@ module Squared
949
1030
  end
950
1031
  when 'refs', 'files'
951
1032
  if flag == :remote
952
- format_desc action, flag, 'remote?,opts*,pattern*'
1033
+ format_desc action, flag, 'remote?|:,opts*,pattern*'
953
1034
  task flag, [:remote] do |_, args|
954
- ls_remote(flag, args.extras, remote: args.remote)
1035
+ remote = args.remote
1036
+ args = if remote && (remote == ':' || !git_grep('remote', remote).empty?)
1037
+ remote = choice_remote(force: true) if remote == ':'
1038
+ args.extras
1039
+ else
1040
+ remote = remotetrack
1041
+ args.to_a
1042
+ end
1043
+ ls_remote(flag, args, remote: remote)
955
1044
  end
956
1045
  else
957
1046
  format_desc(action, flag, 'opts*,pattern*', after: ('pathspec*' if action == 'files'))
@@ -962,10 +1051,11 @@ module Squared
962
1051
  when 'restore'
963
1052
  case flag
964
1053
  when :source
965
- format_desc action, flag, 'ref,opts*,pathspec*'
1054
+ format_desc action, flag, 'commit?|:,opts*,pathspec*'
966
1055
  task flag, [:commit] do |_, args|
967
1056
  commit = commithead args.commit
968
1057
  args = if commit
1058
+ commit = choice_commit if commit == ':'
969
1059
  args.extras
970
1060
  else
971
1061
  commit, opts, files = choice_commit(values: ['Options', ['Pathspec', true]])
@@ -1204,45 +1294,62 @@ module Squared
1204
1294
  end
1205
1295
  end
1206
1296
 
1207
- def clone(*, sync: invoked_sync?('clone'), **)
1208
- return unless clone? && (data = workspace.git_repo(name))
1297
+ def clone(flag = nil, opts = [], sync: invoked_sync?('clone'), dir: nil, ref: nil, **)
1298
+ if flag
1299
+ return unless dir && ref
1300
+
1301
+ url = git_spawn("config --get remote.#{remotetrack}.url")
1302
+ cmd, opts = git_session('clone', worktree: false, opts: opts)
1303
+ op = OptionPartition.new(opts, OPT_GIT[:clone], cmd, project: self, strict: strict?,
1304
+ no: OPT_GIT[:no][:clone])
1305
+ op.add_option('b', ref)
1306
+ .delim
1307
+ .add_quote(url.chomp)
1308
+ .add_path(dir)
1309
+ .clear
1310
+ source
1311
+ else
1312
+ return unless clone? && (data = workspace.git_repo(name))
1209
1313
 
1210
- cmd = git_session('clone', worktree: false)
1211
- opts = data[1].dup
1212
- option('depth', ignore: false) do |val|
1213
- if (n = val.to_i) > 0
1214
- opts[:depth] = n
1314
+ cmd = git_session('clone', worktree: false)
1315
+ opts = data[1].dup
1316
+ option('depth', ignore: false) do |val|
1317
+ if (n = val.to_i) > 0
1318
+ opts[:depth] = n
1319
+ else
1320
+ opts.delete(:depth)
1321
+ end
1322
+ end
1323
+ option('origin', ignore: false) { |val| opts[:origin] = val }
1324
+ if (branch = option('branch', strict: true))
1325
+ opts[:branch] = branch
1326
+ opts.delete(:revision)
1215
1327
  else
1216
- opts.delete(:depth)
1328
+ option('revision', strict: true) do |val|
1329
+ opts[:revision] = val
1330
+ opts.delete(:branch)
1331
+ opts.delete(:mirror)
1332
+ end
1217
1333
  end
1218
- end
1219
- option('origin', ignore: false) { |val| opts[:origin] = val }
1220
- if (branch = option('branch', strict: true))
1221
- opts[:branch] = branch
1222
- opts.delete(:revision)
1223
- else
1224
- option('revision', strict: true) do |val|
1225
- opts[:revision] = val
1226
- opts.delete(:branch)
1227
- opts.delete(:mirror)
1334
+ option('local', strict: true) { |val| opts[:local] = val != '0' }
1335
+ option('bare') { |val| opts[:bare] = val }
1336
+ option('single-branch', ignore: false) do |val|
1337
+ opts[:'single-branch'] = val != '0' && val != 'false'
1338
+ opts.delete(:'no-single-branch')
1228
1339
  end
1340
+ option('no-checkout') do
1341
+ opts[:'no-checkout'] = true
1342
+ opts.delete(:n)
1343
+ end
1344
+ option('no-tags') { opts[:'no-tags'] = true }
1345
+ if append_submodules(from: :clone)
1346
+ opts.delete(:'recurse-submodules') || opts.delete(:'no-recurse-submodules')
1347
+ end
1348
+ append_hash opts
1349
+ cmd << '--quiet' if quiet? || option('quiet')
1350
+ append_value(data[0], path, delim: true)
1351
+ source(sync: sync, banner: sync && !quiet?, multiple: !sync || quiet?)
1229
1352
  end
1230
- option('local', strict: true) { |val| opts[:local] = val != '0' }
1231
- option('bare') { |val| opts[:bare] = val }
1232
- option('single-branch', ignore: false) do |val|
1233
- opts[:'single-branch'] = val != '0' && val != 'false'
1234
- opts.delete(:'no-single-branch')
1235
- end
1236
- option('no-checkout') do
1237
- opts[:'no-checkout'] = true
1238
- opts.delete(:n)
1239
- end
1240
- option('no-tags') { opts[:'no-tags'] = true }
1241
- opts.delete(:'recurse-submodules') || opts.delete(:'no-recurse-submodules') if append_submodules(from: :clone)
1242
- append_hash opts
1243
- cmd << '--quiet' if quiet? || option('quiet')
1244
- append_value(data[0], path, delim: true)
1245
- source(sync: sync, banner: sync && !quiet?, multiple: !sync || quiet?)
1246
1353
  end
1247
1354
 
1248
1355
  def stash(flag = nil, opts = [], sync: invoked_sync?('stash', flag))
@@ -1272,7 +1379,11 @@ module Squared
1272
1379
  first: (matchpathspec if flag == :push))
1273
1380
  case flag
1274
1381
  when :push
1275
- op.readline('Enter message', option: 'message', quote: true) if op.remove(':')
1382
+ if op.remove(':')
1383
+ op.readline('Enter message', option: 'message', quote: true)
1384
+ else
1385
+ append_message
1386
+ end
1276
1387
  append_pathspec op.extras
1277
1388
  when :pop, :apply, :drop, :branch
1278
1389
  if op.remove(':')
@@ -1434,6 +1545,55 @@ module Squared
1434
1545
  end
1435
1546
  end
1436
1547
 
1548
+ def push(flag = nil, opts = [], origin: nil, branch: nil, ref: nil)
1549
+ cmd, opts = git_session('push', opts: opts)
1550
+ op = OptionPartition.new(opts, OPT_GIT[:push], cmd, project: self, strict: strict?, no: OPT_GIT[:no][:push])
1551
+ force = op.arg?('f', 'force', 'force-with-lease')
1552
+ case flag
1553
+ when :origin, :remote
1554
+ exit 1 unless origin && branch
1555
+ unless force
1556
+ repofetch(origin, branch: branch)
1557
+ exit 1 if (branch.start_with?(':') || op.arg?('d', 'delete')) && !confirm_basic('Delete?', branch, 'N')
1558
+ end
1559
+ op.append(origin, branch)
1560
+ .clear(pass: false)
1561
+ when :commit
1562
+ exit 1 unless ref
1563
+ branch ||= git_spawn('name-rev --name-only', ref).chomp
1564
+ raise ArgumentError, message('could not resolve upstream branch', hint: ref) if branch.empty?
1565
+
1566
+ op.append(remotetrack, "#{ref}:#{branch}")
1567
+ .clear(pass: false)
1568
+ when :all
1569
+ op << '--all'
1570
+ op.add_quote(origin) if origin ||= option('origin')
1571
+ op.clear
1572
+ else
1573
+ op << "--#{flag}" if flag
1574
+ op.concat(Array(branch)) if branch
1575
+ origin ||= option('origin')
1576
+ if !op.empty?
1577
+ origin ||= remotetrack
1578
+ unless force
1579
+ i = -1
1580
+ op.each do |val|
1581
+ if !val.include?(':') && repofetch(origin, branch: val, sync: (i += 1) == 0).first.nil?
1582
+ op.errors << val
1583
+ else
1584
+ op.found << val
1585
+ end
1586
+ end
1587
+ end
1588
+ op.add_quote(origin, *op.found)
1589
+ .clear(errors: !force, pass: false)
1590
+ elsif origin
1591
+ op.add_quote(origin)
1592
+ end
1593
+ end
1594
+ source
1595
+ end
1596
+
1437
1597
  def reset(flag, opts = [], refs: nil, ref: nil, mode: nil, commit: nil)
1438
1598
  cmd, opts = git_session('reset', opts: opts)
1439
1599
  case flag
@@ -1469,12 +1629,12 @@ module Squared
1469
1629
  source
1470
1630
  end
1471
1631
 
1472
- def checkout(flag, opts = [], branch: nil, origin: nil, create: nil, commit: nil, detach: nil, merge: false)
1632
+ def checkout(flag, opts = [], origin: nil, branch: nil, create: nil, commit: nil, detach: nil, merge: false)
1473
1633
  cmd, opts = git_session('checkout', opts: opts)
1474
1634
  append_option 'f', 'force', 'merge'
1475
1635
  case flag
1476
1636
  when :branch
1477
- cmd << '--detach' if detach == 'd' || option('detach')
1637
+ cmd << '--detach' if detach == 'd' || option('d', 'detach')
1478
1638
  append_option('track', equals: true)
1479
1639
  cmd << (create ? quote_option(create, branch) : branch) << commit
1480
1640
  when :track
@@ -1502,7 +1662,7 @@ module Squared
1502
1662
  cmd, opts = git_session('tag', opts: opts)
1503
1663
  case flag
1504
1664
  when :add, :sign
1505
- if flag == :sign || option('sign')
1665
+ if flag == :sign
1506
1666
  cmd << '--sign'
1507
1667
  elsif !session_arg?('s', 'sign', 'u', 'local-user')
1508
1668
  cmd << '--annotate'
@@ -1612,10 +1772,29 @@ module Squared
1612
1772
  end
1613
1773
 
1614
1774
  def commit(flag, opts = [], refs: [], ref: nil, squash: nil, pick: nil, message: nil, pass: false)
1615
- fixup = flag == :fixup
1616
- amend = flag.match?(/^amend/) && !fixup
1617
- unless flag == :add || pick == 'reword'
1618
- pathspec = if flag == :all || ((fixup || amend) && refs.size == 1 && refs.first == '*')
1775
+ case flag
1776
+ when :head
1777
+ cmd, opts = git_session('commit', opts: opts)
1778
+ op = OptionPartition.new(opts, OPT_GIT[:commit], cmd, project: self, strict: strict?,
1779
+ no: OPT_GIT[:no][:commit], first: matchpathspec)
1780
+ append_message message
1781
+ if op.arg?('p', 'patch', 'i', 'interactive')
1782
+ op.clear
1783
+ else
1784
+ append_pathspec op.extras
1785
+ end
1786
+ return source
1787
+ when :all
1788
+ pathspec = '--all'
1789
+ when :add
1790
+ pathspec = false
1791
+ when :amend, :'amend-orig'
1792
+ amend = true
1793
+ else
1794
+ pathspec = false if pick == 'reword'
1795
+ end
1796
+ if pathspec.nil?
1797
+ pathspec = if (flag == :fixup || amend) && refs.size == 1 && refs.first == '*'
1619
1798
  '--all'
1620
1799
  elsif (refs = projectmap(refs)).empty?
1621
1800
  raise 'no qualified pathspec'
@@ -1623,8 +1802,8 @@ module Squared
1623
1802
  "-- #{refs.join(' ')}"
1624
1803
  end
1625
1804
  end
1626
- if fixup
1627
- ret = source(git_session('commit', basic_option('fixup', pick ? "#{pick}:#{ref}" : ref), pathspec))
1805
+ if flag == :fixup
1806
+ ret = source(git_session('commit', basic_option('fixup', pick ? task_join(pick, ref) : ref), pathspec))
1628
1807
  source git_output('rebase --autosquash', squash) if ret && squash.is_a?(String)
1629
1808
  return ret
1630
1809
  end
@@ -1634,34 +1813,25 @@ module Squared
1634
1813
 
1635
1814
  message = readline('Enter message', force: true)
1636
1815
  end
1637
- branch = nil
1638
- origin = nil
1639
- upstream = nil
1640
1816
  cmd, opts = git_session('add', opts: opts)
1641
1817
  op = OptionPartition.new(opts, OPT_GIT[:add] + OPT_GIT[:log][:diff_context], cmd,
1642
1818
  project: self, strict: strict?, no: OPT_GIT[:no][:add], first: matchpathspec)
1643
1819
  op << '--verbose' unless silent?
1644
- format = '%(if)%(HEAD)%(then)%(refname:short)...%(upstream:short)...%(upstream:track)%(end)'
1645
- git_spawn 'fetch --no-tags --quiet'
1646
- foreachref('heads', format: format).each do |line|
1647
- next if line.empty?
1648
-
1649
- branch, origin, hint = line.split('...')
1650
- raise message('work tree is not usable', hint: hint[1..-2]) if hint && !hint.match?(/^\[(\D+0,\D+0)\]$/)
1651
-
1652
- if (!origin || origin.empty?) && !dryrun?
1653
- return nil if pass
1820
+ origin, branch = repofetch
1821
+ unless origin || dryrun?
1822
+ return if pass
1654
1823
 
1655
- unless (origin = option('upstream', prefix: 'git', ignore: false))
1656
- if (origin = choice_refs('Choose an upstream', 'remotes', attempts: 1, force: false))
1657
- git_spawn 'branch', quote_option('set-upstream-to', origin)
1658
- break
1659
- end
1824
+ upstream = true
1825
+ origin = option('origin', 'upstream', prefix: 'git', ignore: false)
1826
+ unless origin
1827
+ origin = choice_refs('Choose an upstream', 'remotes', attempts: 1, force: false)
1828
+ if origin
1829
+ git_spawn 'branch', quote_option('set-upstream-to', origin)
1830
+ upstream = false
1831
+ else
1660
1832
  origin = readline('Enter an upstream', force: true)
1661
1833
  end
1662
- upstream = true
1663
1834
  end
1664
- break
1665
1835
  end
1666
1836
  if pathspec
1667
1837
  op << pathspec
@@ -1805,7 +1975,7 @@ module Squared
1805
1975
  out, banner, from = source(io: true)
1806
1976
  first = from_base?('branch')
1807
1977
  grep = first ? [/^\*\s+#{Regexp.escape(head)}\s/] : []
1808
- ret = write_lines(out, grep: grep, banner: banner, first: first) do |line, index|
1978
+ ret = write_lines(out, grep: grep, banner: banner, first: first) do |line, i|
1809
1979
  next line if stdin?
1810
1980
 
1811
1981
  data = line.sub(/^\*?\s+/, '').split(/\s+/, 3)
@@ -1819,7 +1989,7 @@ module Squared
1819
1989
  r3 = write.call($4, $5)
1820
1990
  end
1821
1991
  r1 = nil if r1 == "origin/#{data[0]}"
1822
- ["#{"\n" unless index == 0} Branch: #{a.subhint(r1)}", r2, r3, " Commit: #{b}", "Message: #{md[2]}"]
1992
+ ["#{"\n" unless i == 0} Branch: #{a.subhint(r1)}", r2, r3, " Commit: #{b}", "Message: #{md[2]}"]
1823
1993
  .compact
1824
1994
  .join("\n")
1825
1995
  end
@@ -1915,7 +2085,7 @@ module Squared
1915
2085
  cmd, opts = git_session('rev-parse', opts: opts)
1916
2086
  case flag
1917
2087
  when :commit
1918
- cmd << (size.to_i.zero? ? '--verify' : basic_option('short', [size.to_i, 5].max))
2088
+ cmd << (size.to_i == 0 ? '--verify' : basic_option('short', [size.to_i, 5].max))
1919
2089
  append_commit(ref, head: true)
1920
2090
  when :branch
1921
2091
  cmd << '--abbrev-ref' << '--symbolic-full-name' << shell_quote(case ref
@@ -1958,7 +2128,7 @@ module Squared
1958
2128
  op.add_quote(remote) if remote
1959
2129
  out, banner, from = source(io: true)
1960
2130
  print_item banner
1961
- ret = write_lines(out, grep: op.extras, prefix: "refs/#{flag}/")
2131
+ ret = write_lines(out, grep: op.extras)
1962
2132
  list_result(ret, flag.to_s, grep: op.extras, banner: banner, from: from)
1963
2133
  end
1964
2134
 
@@ -2171,15 +2341,15 @@ module Squared
2171
2341
  choice_index(msg, foreachref(type, *args, format: format), trim: trim, **kwargs)
2172
2342
  end
2173
2343
 
2174
- def choice_commit(count: true, reflog: true, force: true, **kwargs)
2344
+ def choice_commit(msg = 'Choose a commit', range: nil, count: true, reflog: true, force: true, **kwargs)
2175
2345
  kwargs[:attempts] ||= 1 unless force
2176
- cmd = git_output(reflog && env('GIT_REFLOG') ? 'reflog' : 'log')
2346
+ cmd = git_output(reflog && env('GIT_REFLOG') ? 'reflog' : 'log', range)
2177
2347
  cmd << quote_option('format', "#{commitstyle('%h')} %s")
2178
2348
  cmd << basic_option('max-count', env('GIT_COUNT', ARG[:CHOICE])) if count
2179
- ret = choice_index('Choose a commit', git_spawn(cmd, stdout: false), column: /^(\S+)/, force: force, **kwargs)
2349
+ ret = choice_index(msg, git_spawn(cmd, stdout: false), column: /^(\S+)/, force: force, **kwargs)
2180
2350
  case ret
2181
2351
  when Array
2182
- ret.map(&:stripstyle)
2352
+ ret.map { |val| val&.stripstyle }
2183
2353
  when String
2184
2354
  ret.stripstyle
2185
2355
  else
@@ -2264,9 +2434,9 @@ module Squared
2264
2434
  end
2265
2435
  end
2266
2436
 
2267
- def append_pathspec(files = [], target: @session, expect: false, **kwargs)
2437
+ def append_pathspec(files = [], target: @session, expect: false, strict: strict?, **kwargs)
2268
2438
  if session_arg?('pathspec-from-file', target: target)
2269
- OptionPartition.clear(target, files, styles: theme[:inline])
2439
+ OptionPartition.clear(target, files, strict: strict, styles: theme[:inline])
2270
2440
  true
2271
2441
  else
2272
2442
  option('pathspec', target: target) { |val| files = split_escape(val) } if files.empty?
@@ -2308,7 +2478,7 @@ module Squared
2308
2478
  end
2309
2479
  else
2310
2480
  target << case val
2311
- when 'no', '0', 'false'
2481
+ when '0', 'false', 'no'
2312
2482
  '--no-recurse-submodules'
2313
2483
  when 'yes', 'on-demand'
2314
2484
  "--recurse-submodules=#{val}"
@@ -2322,7 +2492,7 @@ module Squared
2322
2492
  def foreachref(path, *args, format: nil, chomp: true)
2323
2493
  format &&= quote_option('format', format)
2324
2494
  ret = git_spawn('for-each-ref', format, *args.concat(Array(path).map { |val| "refs/#{val}" }),
2325
- stdout: workspace.windows?)
2495
+ stdout: windows?)
2326
2496
  if ret.is_a?(String)
2327
2497
  ret.lines(chomp: chomp)
2328
2498
  elsif chomp
@@ -2367,10 +2537,6 @@ module Squared
2367
2537
  ret
2368
2538
  end
2369
2539
 
2370
- def dryrun?(target: @session, prefix: target&.first, **)
2371
- Array(target).include?('--dry-run') || !option('dry-run', target: target, prefix: prefix).nil?
2372
- end
2373
-
2374
2540
  def quiet?(target: @session, **)
2375
2541
  return silent? unless target
2376
2542
 
@@ -2381,6 +2547,25 @@ module Squared
2381
2547
  basepath('.git', *args)
2382
2548
  end
2383
2549
 
2550
+ def repofetch(origin = 'HEAD', branch: nil, sync: true)
2551
+ format = if branch
2552
+ "%(if:equals=#{origin}/#{branch})%(upstream:short)"
2553
+ else
2554
+ "%(if)%(#{origin})"
2555
+ end
2556
+ format += '%(then)%(refname:short)...%(upstream:short)...%(upstream:track)%(end)'
2557
+ git_spawn 'fetch --no-tags --quiet' if sync
2558
+ foreachref('heads', format: format).each do |line|
2559
+ next if line.empty?
2560
+
2561
+ branch, origin, hint = line.split('...')
2562
+ raise message('work tree is not usable', hint: hint[1..-2]) if hint && !hint.match?(/^\[(\D+0,\D+0)\]$/)
2563
+
2564
+ return [origin.empty? ? nil : origin, branch]
2565
+ end
2566
+ []
2567
+ end
2568
+
2384
2569
  def repotrack(origin, branch, quote: true)
2385
2570
  n = origin&.index('/')
2386
2571
  raise message("missing #{origin ? 'branch' : 'remote'} name", hint: origin) unless n && branch
@@ -2391,6 +2576,10 @@ module Squared
2391
2576
  ret
2392
2577
  end
2393
2578
 
2579
+ def remotetrack
2580
+ git_spawn('rev-parse --abbrev-ref @{u}').split('/').first
2581
+ end
2582
+
2394
2583
  def commithash(val)
2395
2584
  val[/\A:(\h{5,40})\z/, 1]
2396
2585
  end