zsh-workers
 help / color / mirror / code / Atom feed
7b76d5a903b18a9142b9a15eefea5620399e5aed blob 44959 bytes (raw)

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
 
#compdef git git-apply git-checkout-index git-commit-tree git-hash-object git-index-pack git-init-db git-merge-index git-mktag git-pack-objects git-prune-packed git-read-tree git-unpack-objects git-update-index git-write-tree git-cat-file git-diff-index git-diff-files git-diff-stages git-diff-tree git-fsck-objects git-ls-files git-ls-tree git-merge-base git-name-rev git-rev-list git-show-index git-tar-tree git-unpack-file git-var git-verify-pack git-clone-pack git-fetch-pack git-http-fetch git-local-fetch git-peek-remote git-receive-pack git-send-pack git-ssh-fetch git-ssh-upload git-update-server-info git-upload-pack git-add git-am git-applymbox git-bisect git-branch git-checkout git-cherry-pick git-clone git-commit git-diff git-fetch git-format-patch git-grep git-log git-ls-remote git-merge git-mv git-octopus git-pull git-push git-rebase git-repack git-reset git-resolve git-revert git-shortlog git-show-branch git-status git-verify-tag git-whatchanged git-applypatch git-archimport git-convert-objects git-cvsimport git-lost-found git-merge-one-file git-prune git-relink git-svnimport git-symbolic-ref git-tag git-update-ref git-check-ref-format git-cherry git-count-objects git-daemon git-get-tar-commit-id git-mailinfo git-mailsplit git-patch-id git-request-pull git-send-email git-stripspace

# Commands not completed:
# git-sh-setup
# git-shell
# git-parse-remote 
# git-rev-parse 

# TODO: most commands need a valid git repository to run, so add a check for it
# so that we can make our handling a little bit cleaner (need to deal with
# GIT_DIR=... stuff as pre-command modifier)

# TODO: suggested zstyles:
#
# zstyle ':completion::*:git-{name-rev,add,rm}:*' ignore-line true

typeset -g nul_arg=

nul_arg='-z[use NUL termination on output]'

typeset -ga diff_args

# TODO: -s and --diff-filter are undocumented
diff_args=(
  '--diff-filter=-[filter to apply to diff]'
  '--find-copies-harder[try harder to find copies]'
  '--name-only[show only names of changed files]'
  '--name-status[show only names and status of changed files]'
  '--pickaxe-all[when -S finds a change, show all changes in that changeset]'
  '-B-[break complete rewrite changes into pairs of given size]: :_guard "[[\:digit\:]]#" size'
  '-C-[detect copies as well as renames with given score]: :_guard "[[\:digit\:]]#" size'
  '-l-[number of rename/copy targets to run]: :_guard "[[\:digit\:]]#" number'
  '-M-[detect renames with given score]: :_guard "[[\:digit\:]]#" size'
  '-O-[output patch in the order of glob-pattern lines in given file]:file:_files'
  '-p[generate diff in patch format]'
  '-R[do a reverse diff]'
  '-S-[look for differences that contain the given string]:string'
  '-s[do not produce any output]'
  '-u[synonym for -p]'
  $nul_arg
)

typeset -g pretty_arg=
pretty_arg='--pretty=-[pretty print commit messages]::pretty print:((raw\:"the raw commits"
                                                                     medium\:"most parts of the messages"
                                                                     short\:"few headers and only subject of messages"
                                                                     full\:"all parts of the commit messages"
                                                                     oneline\:"commit-ids and subject of messages"))'

typeset -g exec_arg=
exec_arg='--exec=-[specify path to git-upload-pack on remote side]:remote path'

typeset -ga fetch_args

fetch_args=(
  '-a[fetch all objects]'
  '-c[fetch commit objects]'
  '--recover[recover from a failed fetch]'
  '-t[fetch trees associated with commit objects]'
  '-v[show what is downloaded]'
  '-w[write out the given commit-id to the given file]:new file'
)

typeset -ga merge_strategy

merge_strategy=(
  '(-s --strategy)'{-s,--strategy=}'[use given merge strategy]:strategy:(octopus recursive resolve stupid)')

typeset -ga force_ref_arg

force_ref_arg=('(-f --force)'{-f,--force}'[allow refs that are not ancestors to be updated]')

typeset -ga tags_fetch_arg

tags_fetch_arg=('(-t --tags)'{-t,--tags}'[fetch remote tags]')

# TODO: either skip uninteresting commands or skip the description - the list
# is just too long
_git_commands () {
  local -a commands

  commands=(
    'add:add paths to the index'
    'am:apply patches from a mailbox (cooler than applymbox)'
    'apply:apply patch on a git index file and a work tree'
    'applymbox:apply patches from a mailbox'
    'applypatch:apply one patch extracted from an e-mail'
    'archimport:import an Arch repository into git'
    'bisect:find the change that introduced a bug'
    'branch:create and show branches'
    'cat-file:provide content or type information for repository objects'
    'check-ref-format:makes sure that a reference-name is well formed'
    'checkout:checkout and switch to a branch'
    'checkout-index:copy files from the index to the working directory'
    'cherry:find commits not merged upstream'
    'cherry-pick:cherry-pick the effect of an existing commit'
    'clone:clones a repository into a new directory'
    'clone-pack:clones a repository into the current repository (transport)'
    'commit:record changes to the repository'
    'commit-tree:creates a new commit object'
    'convert-objects:converts old-style git repository'
    'count-objects:count unpacked objects and display their disk consumption'
    'cvsimport:import a CVS "repository" into a git repository'
    'daemon:starts a really simple server for git repositories'
    'diff:show changes between commits, commit and working tree, etc.'
    'diff-files:compares files in the working tree and the index'
    'diff-index:compares content and mode of blobs between index and repository'
    'diff-stages:compares two "merge states" in the index file'
    'diff-tree:compares the content and mode of blobs found via two tree objects'
    'fetch:download objects and a head from another repository'
    'fetch-pack:receive missing objects from another repository'
    'format-patch:prepare patches for e-mail submission'
    'fsck-objects:verifies the connectivity and validity of the objects in the database'
    'get-tar-commit-id:extract commit ID from an archive created using tar-tree'
    'grep:print lines matching a pattern'
    'hash-object:computes the object ID from a file'
    'http-fetch:downloads a remote git repository via HTTP'
    'index-pack:build pack index file for an existing packed archive'
    'init-db:creates an empty git object database'
    'local-fetch:duplicates another git repository on a local system'
    'log:shows commit logs'
    'lost-found:recovers lost references that luckily have not yet been pruned'
    'ls-files:information about files in the index/working directory'
    'ls-remote:shows references in a remote or local repository'
    'ls-tree:displays a tree object in human-readable form'
    'mailinfo:extracts patch from a single e-mail message'
    'mailsplit:splits an mbox file into a list of files'
    'merge:grand unified merge driver'
    'merge-base:finds a good common ancestor as possible for a merge'
    'merge-index:runs a merge for files needing merging'
    'merge-one-file:standard helper-program to use with merge-index'
    'mktag:creates a tag object'
    'mv:moves or renames a file, directory, or symlink'
    'name-rev:find symbolic names for given revisions'
    'octopus:merges more than two commits'
    'pack-objects:creates a packed archive of objects'
    'parse-remote:routines to help parsing $GIT_DIR/remotes/'
    'patch-id:computes unique ID for a apatch'
    'peek-remote:lists references on a remote repository using the upload-pack protocol'
    'prune:prunes all unreachable objects from the object database'
    'prune-packed:removes extra objects that are already in pack files'
    'pull:fetch from and merge with a remote repository'
    'push:update remote refs along with associated objects'
    'read-tree:reads tree information into the directory index'
    'rebase:rebases local commits to new upstream head'
    'receive-pack:command invoked by send-pack to receive what is pushed to it'
    'relink:hardlinks acommon objects in local repositories'
    'repack:packs unpacked objects in a repository'
    'request-pull:generates a summary of pending changes'
    'reset:resets current HEAD to the specified state'
    'resolve:merges two commits'
    'rev-list:lists commit object in reverse chronological order'
    'rev-parse:picks out and massages parameters for other git commands'
    'revert:reverts an existing commit'
    'send-email:sends patch-e-mails out of "format-patch --mbox" output'
    'send-pack:pushes to a remote repository, intelligently'
    'shortlog:summarizes git log output'
    'show-branch:shows branches and their commits'
    'show-index:displays contents of a pack idx file'
    'ssh-fetch:pulls from a remote repository over an SSH connection'
    'ssh-upload:helper "server-side" program used by ssh-fetch'
    "status:shows the working-tree's status"
    'stripspace:filters out empty lines'
    'svnimport:imports a SVN repository into git'
    'symbolic-ref:reads and modifies symbolic references'
    'tag:creates a tag object signed with GPG'
    'tar-tree:creates a tar archive of the files in the named tree'
    "unpack-file:creates a temporary file with a blob's contents"
    'unpack-objects:unpacks objects out of a packed archive'
    'update-index:modifies the index in some given way'
    'update-ref:updates the object name stored in a reference safely'
    'update-server-info:updates auxiliary information on a dumb server'
    'upload-pack:command invoked by clone-pack and fetch-pack'
    'var:displays a git logical variable'
    'verify-pack:validates packed git archive files'
    'verify-tag:checks the GPG signature of a tag'
    'whatchanged:shows commit-logs and differences they introduce'
    'write-tree:creates a tree from the current index')

  _describe -t commands 'git command' commands && ret=0
}

# TODO: this needs to be cleaned up and fixed
local curcontext=$curcontext ret=1

if [[ $words[1] == git ]]; then
  if (( CURRENT == 2 )); then
    _git_commands
  else
    shift words
    (( CURRENT-- ))
    curcontext="${curcontext%:*:*}:git-$words[1]:"
    _call_function ret _git-$words[1]
  fi
else
  _call_function ret _$words[1]
fi

_git-apply () {
  _arguments \
    $nul_arg \
    '*--apply[apply patches that would otherwise not be applied]' \
    '*--check[check if patches are applicable]' \
    '*--exclude=-[skip files matching specified pattern]:file pattern' \
    '*--index[make sure that the patch is applicable to the index]' \
    '*--index-info[output information about original version of a blob if available]' \
    '*--no-merge[do not use merge behavior]' \
    '*--numstat[same as --stat but in decimal notation and complete pathnames]' \
    '*--stat[output diffstat for the input]' \
    '*--summary[output summary of git-diff extended headers]' \
    '*:file:_files' && ret=0
}

_git-checkout-index () {
  _arguments -S \
    '(-a --all :)'{-a,--all}'[check out all files in the index]' \
    '(-f --force)'{-f,--force}'[force overwrite of existing files]' \
    '(-n --no-create)'{-n,--no-create}'[do not checkout new files]' \
    '(-q --quiet)'{-q,--quiet}'[do not complain about existing files or missing files]' \
    '(-u --index)'{-u,--index}'[update stat information in index]' \
    '--prefix=-[prefix to use when creating files]:directory:_directories' \
    '*:file:_files' && ret=0
}

_git-commit-tree () {
  if (( CURRENT == 2 )); then
    __git_trees && ret=0
  elif [[ $words[CURRENT-1] == -p ]]; then
    local expl
    _description commits expl 'parent commit'
    __git_objects $expl && ret=0
  else
    compadd - '-p'
  fi
}

_git-hash-object () {
  _arguments \
    '-t[the type of object to create]:object type:((blob\:"a blob of data"
                                                    commit\:"a tree with parent commits"
                                                    tag\:"a symbolic name for another object"
                                                    tree\:"a recursive tree of blobs"))' \
    '-w[write the object to the object database]' \
    ':file:_files' && ret=0
}

_git-index-pack () {
  _arguments \
    '-o[write generated pack index into specified file]' \
    ':pack file:_files -g "*.pack"' && ret=0
}

_git-init-db () {
  _arguments \
    '--template=-[directory to use as a template for the object database]:directory:_directories' && ret=0
}

_git-merge-index () {
  if (( CURRENT > 2 )) && [[ $words[CURRENT-1] != -[oq] ]]; then
    _arguments -S \
      '(:)-a[run merge against all files in the index that need merging]' \
      '*:index file:__git_files' && ret=0
  else
    typeset -a arguments

    (( CURRENT == 2 )) && arguments+='-o[skip failed merges]'
    (( CURRENT == 2 || CURRENT == 3 )) && arguments+='(-o)-q[do not complain about failed merges]'
    (( 2 <= CURRENT && CURRENT <= 4 )) && arguments+='*:merge program:_files -g "*(*)"'

    _arguments -S $arguments && ret=0
  fi
}

_git-mktag () {
  _message 'no arguments allowed; only accepts tags on standard input'
}

_git-pack-objects () {
  _arguments \
    '--depth=-[maximum delta depth]' \
    '--incremental[ignore objects that have already been packed]' \
    '--non-empty[only create a package if it contains at least one object]' \
    '--local[similar to --incremental, but only ignore unpacked non-local objects]' \
    '--window=-[number of objects to use per delta compression]' \
    '(:)--stdout[write the pack to standard output]' \
    ':base-name:_files' && ret=0
}

_git-prune-packed () {
  _arguments \
    '-n[only list the objects that would be removed]' && ret=0
}

_git-read-tree () {
  if (( CURRENT == 2 )); then
    _arguments \
      '--reset[perform a merge, not just a read, ignoring unmerged entries]' \
      '--trivial[only perform trivial merges]' \
      '-m[perform a merge, not just a read]' \
      ':tree-ish:__git_tree_ishs' && ret=0
  elif [[ $words[2] == (-m|--reset) ]]; then
    _arguments \
      '-i[update only the index; ignore changes in work tree]' \
      '-u[update the work tree after successful merge]' \
      '2:first tree-ish to be read/merged:__git_tree_ishs' \
      '3:second tree-ish to be read/merged:__git_tree_ishs' \
      '4:third tree-ish to be read/merged:__git_tree_ishs' && ret=0
  else
    _message 'no more arguments'
  fi
}

_git-unpack-objects () {
  _arguments \
    '-n[only list the objects that would be unpacked]' \
    '-q[run quietly]' && ret=0
}

_git-update-index () {
  local -a refreshables

  if (( $words[(I)--refresh] )); then
    refreshables=(
      '--ignore-missing[ignore missing files when refreshing the index]'
      '--unmerged[if unmerged changes exists, ignore them instead of exiting]'
      '-q[run quietly]')
  fi

  _arguments -S \
    $refreshables \
    '--add[add files not already in the index]' \
    '--cacheinfo[insert information directly into the cache]: :_guard "[0-7]#" "octal file mode": :_guard "[[\:xdigit\:]]#" "object id":file:_files' \
    '--chmod=-[set the execute permissions on the updated files]:permission:((-x\:executable +x\:"not executable"))' \
    '(--remove)--force-remove[remove files from both work tree and the index]' \
    '--index-info[read index information from stdin.]' \
    '--info-only[only insert files object-IDs into index]' \
    '--refresh[refresh the index]' \
    '(--force-remove)--remove[remove files that are in the index but are missing from the work tree]' \
    '--replace[replace files already in the index if necessary]' \
    '--stdin[read list of paths from standard input]' \
    '--verbose[report what is being added and removed from the index]' \
    '-z[paths are separated with NUL instead of LF for --stdin]' \
    '*:file:_files' && ret=0
}

_git-write-tree () {
  _arguments \
    '--missing-ok[ignore objects in the index that are missing in the object database]' && ret=0
}

_git-cat-file () {
  if (( CURRENT == 2 )); then
    _arguments \
      '-t[show the type of the given object]' \
      '-s[show the size of the given object]' \
      '*: :_values "object type" blob commit tag tree' && ret=0
  elif (( CURRENT == 3 )); then
    __git_objects && ret=0
  else
    _message 'no more arguments'
  fi
}

_git-diff-index () {
  _arguments -S \
    $diff_args \
    '--cached[do not consider the work tree at all]' \
    '-m[flag non-checked-out files as up-to-date]' \
    ':tree-ish:__git_tree_ishs' \
    '*:index file:__git_files' && ret=0
}

_git-diff-files () {
  _arguments \
    $diff_args \
    '-q[do not complain about nonexisting files]' \
    '*:file:_files' && ret=0
}

_git-diff-stages () {
  _arguments \
    $diff_args \
    ':stage 1:__git_stages' \
    ':stage 2:__git_stages' \
    '*:index file:__git_files' && ret=0
}

_git-diff-tree () {
  local curcontext=$curcontext state line
  typeset -A opt_args

  _arguments -S \
    $diff_args \
    $pretty_arg \
    '--no-commit-id[skip output of commit IDs]' \
    '--root[show diff against the empty tree]' \
    '--stdin[read commit and tree information from standard input]' \
    '-m[show merge commits]' \
    '-r[recurse into subdirectories]' \
    '(-r)-t[show tree entry itself as well as subtrees (implies -r)]' \
    '-v[show verbose headers]' \
    ':tree-ish:__git_tree_ishs' \
    '*::file:->files' && ret=0

  case $state in
    files)
      if (( $#line > 2 )); then
        # TODO: this is probably just stupid to do.
        # What'd be nice would be
        # common files:
        #   ...
        # original tree:
        #   ...
        # new tree:
        #   ...
        _alternative \
          "original tree:original tree:__git_tree_files $line[1]" \
          "new tree:new tree:__git_tree_files $line[2]" && ret=0
      else
        _alternative \
          ': :__git_tree_ishs' \
          ": :__git_tree_files $line[1]" && ret=0
      fi
      ;;
  esac
}

_git-fsck-objects () {
  _arguments -S \
    '--cache[consider objects recorded in the index as head nodes for reachability traces]' \
    '(--standalone)--full[check all object directories]' \
    '--root[show root nodes]' \
    '(--full)--standalone[check only the current object directory]' \
    '--strict[do strict checking]' \
    '--tags[show tags]' \
    '--unreachable[show objects that are unreferenced in the object database]' \
    '*:object:__git_objects' && ret=0
}

_git-ls-files () {
  _arguments -S \
    $nul_arg \
    '(-c --cached)'{-c,--cached}'[show cached files in the output]' \
    '(-d --deleted)'{-d,--deleted}'[show deleted files in the output]' \
    '(-i --ignored)'{-i,--ignored}'[show ignored files in the output]' \
    '(-k --killed)'{-k,--killed}'[show killed files in the output]' \
    '(-m --modified)'{-m,--modified}'[show modified files in the output]' \
    '(-o --others)'{-o,--others}'[show other files in the output]' \
    '(-s --stage)'{-s,--stage}'[show stage files in the output]' \
    '-t[identify each files status]' \
    '(-u --unmerged)'{-u,--unmerged}'[show unmerged files in the output]' \
    '*'{-x,--exclude=-}'[skip files matching given pattern]:file pattern' \
    '*'{-X,--exclude-from=-}'[skip files matching patterns in given file]:file:_files' \
    '*--exclude-per-directory=-[skip directories matching patterns in given file]:file:_files' \
    '*:index file:__git_files' && ret=0
}

_git-ls-tree () {
  local curcontext=$curcontext state line
  typeset -A opt_args

  _arguments \
    $nul_arg \
    '-d[do not show children of given tree]' \
    '-r[recurse into subdirectories]' \
    ':tree-ish:__git_tree_ishs' \
    '*:tree file:->files' && ret=0

  case $state in
    files)
      __git_tree_files $line[1] && ret=0
      ;;
  esac
}

_git-merge-base () {
  _arguments \
    '(-a --all)'{-a,--all}'[show all common ancestors]' \
    ':commit 1:__git_commits' \
    ':commit 2:__git_commits' && ret=0
}

_git-name-rev () {
  _arguments -S \
    '--tags[only use tags to name the commits]' \
    '(--stdin :)--all[list all commits reachable from all refs]' \
    '(--all :)--stdin[read from stdin and append revision-name]' \
    '(--stdin --all)*:commit-ish:__git_revisions' && ret=0
}

# TODO: --no-merges undocumented
_git-rev-list () {
  if (( $words[(I)--] && $words[(I)--] != CURRENT )); then
    _arguments \
      '*:index file:__git_files' && ret=0
  else
    local show_breaks

    (( $words[(I)--merge-order] )) && show_breaks='--show-breaks[show commit prefixes]'
    _arguments -S \
      '--all[show all commits from refs]' \
      '--bisect[show only the middlemost commit object]' \
      '(--sparse)--dense[this is the inverse of --sparse, and is also the default]' \
      '(--pretty)--header[show commit headers]' \
      '--objects[show object ids of objects referenced by the listed commits]' \
      '--max-age[maximum age of commits to output]: :_guard "[[\:digit\:]]#" number' \
      '--max-count[maximum number of commits to output]: :_guard "[[\:digit\:]]#" timestamp' \
      '(--topo-order)--merge-order[decompose into minimal and maximal epochs]' \
      '--min-age[minimum age of commits to output]: :_guard "[[\:digit\:]]#" timestamp' \
      '--parents[show parent commits]' \
      '(--header)'$pretty_arg \
      '(--dense)--sparse[when paths are given, output only commits that changes any of them]' \
      '(--merge-order)--topo-order[show commits in topological order]' \
      $show_breaks \
      '--unpacked[show only unpacked commits]' \
      '*:commit id:__git_commits2' && ret=0
  fi
}

_git-show-index () {
  _message 'no arguments allowed; accepts index file on standard input'
}

_git-tar-tree () {
  _arguments \
    ':tree-ish:__git_tree_ishs' \
    ':base-name:_files' && ret=0
}

_git-unpack-file () {
  _arguments \
    ':blob id:__git_blobs' && ret=0
}

_git-var () {
  _arguments \
    '(:)-l[show logical variables]' \
    '(-):variable:((GIT_AUTHOR_IDENT\:"name and email of the author" \
                    GIT_COMMITTER_IDENT\:"name and email of committer"))' && ret=0
}

_git-verify-pack () {
  _arguments -S \
    '-v[show objects contained in pack]' \
    '*:index file:_files -g "*.idx"' && ret=0
}
 
__git-clone_or_fetch-pack () {
  _arguments \
    $exec_arg \
    ':remote repository:__git_remote_repository' \
    '*:head:__git_heads' && ret=0
}

_git-clone-pack () {
  __git-clone_or_fetch-pack
}

_git-fetch-pack () {
  __git-clone_or_fetch-pack
}

# TODO: __git_commits appropriate here?  Probably not, as this should be a
# remote commit, but perhaps good enough?
__git-http_or_ssh-fetch () {
  _arguments \
    $fetch_args \
    ':commit id:__git_commits' \
    ':URL:_urls' && ret=0
}

_git-http-fetch () {
  __git-http_or_ssh-fetch
}

_git-local-fetch () {
  _arguments \
    $fetch_args \
    '-l[hard-link objects]' \
    '-n[do not copy objects]' \
    '-s[sym-link objects]' \
    ':commit id:__git_commits' \
    ':directory:_directories' && ret=0
}

_git-peek-remote () {
  _arguments \
    $exec_arg \
    ':remote repository:__git_remote_repository' && ret=0
}

_git-receive-pack () {
  _arguments \
    ':directory:_directories' && ret=0
}

_git-send-pack () {
  _arguments \
    $exec_arg \
    '--all[update all refs that exist locally]' \
    '--force[update remote orphaned refs]' \
    ':remote repository:__git_remote_repository' \
    '*:remote refs' && ret=0
}

# TODO: git-shell, but that's only invoked by other git commands.

_git-ssh-fetch () {
  __git-http_or_ssh-fetch
}

_git-ssh-upload () {
  __git-http_or_ssh-fetch
}

_git-update-server-info () {
  _arguments \
    '(-f --force)'{-f,--force}'[update the info files from scratch]'
}

_git-upload-pack () {
  _arguments \
    ':directory:_directories' && ret=0
}

_git-add () {
  _arguments \
    '-n[do not actually add files; only show which ones would be added]' \
    '-v[show files as they are added]' \
    '*:file:_files -g "*(^e:__git_is_indexed:)"' && ret=0
}

_git-am () {
  _arguments \
    '--3way[use 3-way merge if patch does not apply cleanly]' \
    '--dotest=-[use given directory as working area instead of .dotest]:directory:_directories' \
    '--interactive[apply patches interactively]' \
    '--keep[do not modify Subject: header]' \
    '--signoff[add Signed-off-by: line to the commit message]' \
    '--skip[skip the current patch]' \
    '--utf8[encode commit information in UTF-8]' \
    '*:mbox file:_files' && ret=0
}

_git-applymbox () {
  _arguments \
    '-k[do not modify Subject: header]' \
    '-m[apply patches with git-apply and fail if patch is unclean]' \
    '-q[apply patches interactively]' \
    '-u[encode commit information in UTF-8]' \
    '(1)-c[restart command after fixing an unclean patch]:patch:_files -g ".dotest/0*"' \
    ':mbox file:_files' \
    '::signoff file:__git_signoff_file' && ret=0
}

_git-bisect () {
  local bisect_cmds

  bisect_cmds=(
    bad:"mark current or given revision as bad"
    good:"mark current or given revision as good"
    log:"show the log of the current bisection"
    next:"find next bisection to test and check it out"
    replay:"replay a bisection log"
    reset:"finish bisection search and return to the given branch (or master)"
    start:"reset bisection state and start a new bisection"
    visualize:"show the remaining revisions in gitk"
  )

  if (( CURRENT == 2 )); then
    _describe -t command "git-bisect commands" bisect_cmds && ret=0
  else
    case $words[2] in
      (bad)
        _arguments \
          '2:revision:__git_commits' && ret=0
        ;;
      (good)
        _arguments \
          '*:revision:__git_commits' && ret=0
        ;;
      (replay)
        _arguments \
          '2:file:_files' && ret=0
        ;;
      (reset)
        _arguments \
          '2:branch:__git_heads' && ret=0
        ;;
      (*)
        _nothing
        ;;
    esac
  fi
}

_git-branch () {
  _arguments \
    '(-D)-d[delete a branch, which must be fully merged]' \
    '(-d)-D[delete a branch]' \
    ':branch-name' \
    ':base branch:__git_revisions' && ret=0
}

_git-checkout () {
  _arguments \
    '-f[force a complete re-read]' \
    '-b[create a new branch based at given branch]:branch-name' \
    ':branch:__git_revisions' \
    '*:file:_files' && ret=0
}

_git-cherry-pick () {
  _arguments \
    '(-n --no-commit)'{-n,--no-commit}'[do not make the actually commit]' \
    '(-r --replay)'{-r,--replay}'[use the original commit message intact]' \
    ':commit:__git_revisions' && ret=0
}

_git-clone () {
  local -a shared

  if (( $words[(I)(-l|--local)] )); then
    shared=('(-s --shared)'{-s,--shared}'[share the objects with the source repository]')
  fi

  _arguments \
    '(-l --local)'{-l,--local}'[perform a local cloning of a repository]' \
    $shared
    '(-q --quiet)'{-q,--quiet}'[operate quietly]' \
    '-n[do not checkout HEAD after clone is complete]' \
    '(-u --upload-pack)'{-u,--uploadpack}'[specify path to git-upload-pack on remote side]:remote path' \
    ':repository:__git_any_repositories' \
    ':directory:_directories' && ret=0
}

_git-commit () {
  _arguments -S \
    '(-a --all)'{-a,--all}'[update all paths in the index file]' \
    '(-s --signoff)'{-s,--signoff}'[add Signed-off-by line at the end of the commit message]' \
    '(-v --verify -n --no-verify)'{-v,--verify}'[look for suspicious lines the commit introduces]' \
    '(-n --no-verify -v --verify)'{-n,--no-verify}'[do not look for suspicious lines the commit introduces]' \
    '(-e --edit)'{-e,--edit}'[edit the commit message before committing]' \
    '*:file:_files' \
    - '(message)' \
      '(-c -C --reedit-message --reuse-message)'{-c,--reedit-message=}'[use existing commit object and edit log message]:commit id:__git_commits' \
      '(-c -C --reedit-message --reuse-message)'{-C,--reuse-message=}'[use existing commit object with same log message]:commit id:__git_commits' \
      '(-F --file)'{-F,--file=}'[read commit message from given file]:file:_files' \
      '(-m --message)'{-m,--message=}'[use the given message as the commit message]:message' && ret=0
}

# TODO: __git_files should be __git_tree_files (do like in git-diff-tree and
# such)
_git-diff () {
  _arguments \
    $diff_args \
    '::original revision:__git_revisions' \
    '::new revision:__git_revisions' \
    '*:index file:__git_files' && ret=0
}

_git-fetch () {
  _arguments \
    '(-a --append)'{-a,--append}'[append fetched refs instead of overwriting]' \
    $force_ref_arg \
    $tags_fetch_arg \
    '(-u --update-head-ok)'{-u,--update-head-ok}'[allow updates of current branch head]' \
    ':repository:__git_any_repositories' \
    '*:refspec:__git_ref_specs' && ret=0
}

# TODO: should support R1..R2 syntax
_git-format-patch () {
  _arguments \
    '(-a --author)'{-a,--author}'[output From: header for your own commits as well]' \
    '(-d --date)'{-d,--date}'[output Date: header for your own commits as well]' \
    '(-h --help)'{-h,--help}'[display usage information]' \
    '(-k --keep-subject)'{-k,--keep-subject}'[do not strip/add \[PATCH\] from the first line of the commit message]' \
    '(-m --mbox)'{-m,--mbox}'[use true mbox formatted output]' \
    '(-n --numbered)'{-n,--numbered}'[name output in \[PATCH n/m\] format]' \
    '(-o --output-directory --stdout)'{-o,--output-directory}'[store resulting files in given directory]:directory:_directories' \
    '(-o --output-directory --mbox)--stdout[output the generated mbox on standard output (implies --mbox)]' \
    ':their revision:__git_revisions' \
    '::my revision:__git_revisions' && ret=0
}

# TODO: something better
_git-grep () {
  service=grep _grep
  ret=0
}

# TODO: this isn't strictly right, but close enough
_git-log () {
  _git-rev-list
}

# TODO: repository needs fixing
_git-ls-remote () {
  _arguments \
    '(-h --heads)'{-h,--heads}'[show only refs under refs/heads]' \
    '(-t --tags)'{-t,--tags}'[show only refs under refs/tags]' \
    ':repository:__git_any_repositories' \
    '*: :__git_references' && ret=0
}

_git-merge () {
  _arguments \
    '(-n --no-summary)'{-n,--no-summary}'[do not show diffstat at end of merge]' \
    $merge_strategy \
    ':merge message' \
    ':head:__git_revisions' \
    '*:remote:__git_revisions' && ret=0
}

_git-mv () {
  _arguments \
    '-f[force renaming/moving even if targets exist]' \
    '-k[skip move/renames that would lead to errors]' \
    '-n[only show what would happen]' \
    '*:index file:__git_files' && ret=0
}

_git-octupus () {
  _nothing
}

_git-pull () {
  _arguments \
    $merge_strategy \
    $force_ref_arg \
    $tags_fetch_arg \
    '(-a --append)'{-a,--append}'[append ref-names and object-names to .git/FETCH_HEAD]' \
    '--no-commit[do not commit the merge]' \
    '(-n --no-summary)'{-n,--no-summary}'[do not show diffstate at end of merge]' \
    '(-u,--update-head-ok)'{-u,--update-head-ok}'[allow updating of head to current branch]' \
    ':repository:__git_any_repositories' \
    '*:refspec:__git_ref_specs' && ret=0
}

_git-push () {
  _arguments \
    $force_ref_arg \
    '--all[fetch all refs]' \
    ':repository:__git_any_repositories' \
    '*:refspec:__git_ref_specs' && ret=0
}

_git-rebase () {
  _arguments \
    ':upstream branch:__git_revisions' \
    '::working branch:__git_revisions' && ret=0
}

_git-repack () {
  _arguments \
    '-a[pack all objects into a single pack]' \
    '-d[remove redundant packs after packing]' \
    '-l[ignore unpacked non-local objects]' \
    '-n[do not update server information]' && ret=0
}

_git-reset () {
  _arguments \
    '(        --soft --hard)--mixed[like --soft but report what has not been updated (default)]' \
    '(--mixed        --hard)--soft[do not touch the index file nor the working tree]' \
    '(--mixed --soft       )--hard[match the working tree and index to the given tree]' \
    ':commit-ish:__git_revisions' && ret=0
}

_git-resolve () {
  _arguments \
    ':current commit:__git_revisions' \
    ':merged commit:__git_revisions' \
    ':commit message'
}

_git-revert () {
  _arguments \
    '(-n --no-commit)'{-n,--no-commit}'[do not commit the reversion]'
    '(-r --replay)'{-r,--replay}'[use the original commit message intact]' \
    ':commit:__git_revisions' && ret=0
}

_git-shortlog () {
  _nothing
}

_git-show-branch () {
  _arguments \
    '--all[show all refs under $GIT_DIR/refs]' \
    '--heads[show all refs under $GIT_DIR/refs/heads]' \
    '--independent[show only the reference that can not be reached from any of the other]' \
    '--list[do not display any commit ancestry]' \
    '--merge-base[act like "git-merge-base -a" but with two heads]' \
    '--more=-[go given number of commit beyond common ancestor (no ancestry if negative)]:number' \
    '--no-name[do not show naming strings for each commit]' \
    '--sha1-name[name commits with unique prefix of object names]' \
    '--topo-order[show commits in topological order]' \
    '--tags[show all refs under $GIT_DIR/refs/tags]' \
    '*:reference:__git_revisions' && ret=0
}

_git-status () {
  _nothing
}

_git-verify-tag () {
  _arguments \
    ':tag:__git_tag_ids' && ret=0
}

# TODO: this should be a combination of git-rev-list and git-diff-tree
_git-whatchanged () {
}

_git-applypatch () {
  _arguments \
    ':message file:_files' \
    ':patch file:_files' \
    ':info file:_files' \
    '::signoff file:_files' && ret=0
}

# TODO: archive/branch can use _arch_archives perhaps?
_git-archimport () {
  _arguments \
    '-h[display usage information]' \
    '-v[produce verbose output]' \
    '-T[create a tag for every commit]' \
    '-t[use given directory as temporary directory]:directory:_directories' \
    ':archive/branch' \
    '::archive/branch'
}

_git-convert-objects () {
  _arguments \
    ':object:__git_objects'
}

# TODO: _cvs_root for -d would be nice
_git-cvsimport () {
  _arguments \
    '-C[specify the git repository to import into]:directory:_directories' \
    '-d[specify the root of the CVS archive]:cvsroot' \
    '-h[display usage information]' \
    '-i[do not perform a checkout after importing]' \
    '-k[remove keywords from source files in the CVS archive]' \
    '-u[convert underscores in tag and branch names to dots]' \
    '-M[attempt to detect merges based on the commit message with custom pattern]:pattern' \
    '-m[attempt to detect merges based on the commit message]' \
    '-o[specify the branch into which you wish to import]:branch' \
    '-p[specify additionaly options for cvsps]:cvsps-options' \
    '-s[substitute the "/" character in branch names with given substitution]:substitute' \
    '-v[produce verbose output]' \
    '-z[specify timestamp fuzz factor to cvsps]:fuzz-factor' \
    ':cvsmodule' && ret=0
}

# TODO: documentation is weird
_git-lost-found () {
  _message "awaiting better documentation before proceeding..."
}

# TODO: something better
_git-merge-one-file () {
  _message "you probably should not be issuing this command"
}

_git-prune () {
  _arguments -S \
    '-n[do not remove anything; just report what would have been removed]' && ret=0
}

_git-relink () {
  _arguments \
    '--safe[stop if two objects with the same hash exist but have different sizes]' \
    '*:directory:_directories' && ret=0
}

# TODO: import stuff from _svn
_git-svnimport () {
  _arguments \
    '-b[specify the name of the SVN branches directory]:directory:_directories' \
    '-C[specify the git repository to import into]:directory:_directories' \
    '-D[use direct HTTP-requests if possible]:path' \
    '-d[use direct HTTP-requests if possible for logs only]:path' \
    '-h[display usage information]' \
    '-i[do not perform a checkout after importing]' \
    '-l[limit the number of SVN changesets to pull]: :_guard "[[\:digit\:]]#" number' \
    '-o[specify the branch into which you wish to import]:branch' \
    '-M[attempt to detect merges based on the commit message with custom pattern]:pattern' \
    '-m[attempt to detect merges based on the commit message]' \
    '-s[specify the change number to start importing from:start-revision' \
    '-t[specify the name of the SVN trunk]:trunk:_directories' \
    '-T[specify the name of the SVN tags directory]:directory:_directories' \
    '-v[produce verbose output]' \
    ':svn-repositry-url:_urls' \
    '::directory:_directories' && ret=0
}

# TODO: how do we complete argument 1?
# TODO: argument 2 should be __git_heads, but with full path
_git-symbolic-ref () {
  _arguments \
    ':symbolic reference' \
    ':reference' && ret=0
}

# TODO: first argument right?
# TODO: document options once they are in man
# key-id for -u could perhaps be completed from _gpg somehow
_git-tag () {
  local message=

  if (( $words[(I)-[asu]] )); then
    message='-m[specify tag message]'
  fi

  _arguments \
    $message \
    ':tag-name:__git_tags' \
    '::head:__git_revisions' \
    - '(creation)' \
      '-a[annotate]' \
      '-f[create a new tag even if one with the same name already exists]' \
      '-s[annotate and sign]' \
      '-u[annotate and sign with given key-id]:key-id' \
    - '(deletion)' \
      '-d[delete]:tag:__git_tags' && ret=0
}

_git-update-ref () {
  _arguments \
    ':symbolic reference:__git_revisions' \
    ':new reference:__git_revisions' \
    '::old reference:__git_revisions' && ret=0
}

_git-check-ref-format () {
  _arguments \
    ':reference:__git_revisions' && ret=0
}


_git-cherry () {
  _arguments \
    '-v[be verbose]' \
    ':upstream:__git_revisions' \
    '::head:__git_revisions' && ret=0
}

_git-count-objects () {
  _nothing
}

# TODO: do better than _directory?  The directory needs to be a git-repository,
# so one could check for a required file in the given directory.
_git-daemon () {
  _arguments -S \
    '--export-all[allow pulling from all repositories without verification]' \
    '(--port)--inetd[run server as an inetd service]' \
    '--init-timeout=-[specify timeout between connection and request]' \
    '--port=-[specify port to listen to]' \
    '--syslog[log to syslog instead of stderr]' \
    '--timeout=-[specify timeout for sub-requests]' \
    '--verbose[log details about incoming connections and requested files]' \
    '*:repository:_directory' && ret=0
}

_git-get-tar-commit-id () {
  _message 'no arguments allowed; accepts tar-file on standard input'
}

_git-mailinfo () {
  _arguments \
    '-k[do not strip/add \[PATCH\] from the first line of the commit message]' \
    '-u[encode commit information in UTF-8]' \
    ':message file:_files' \
    ':patch file:_files' && ret=0
}

_git-mailsplit () {
  _arguments \
    '-d-[specify number of leading zeros]: :_guard "[[\:digit\:]]#" "precision' \
    ':mbox file/directory:_files' \
    '::directory:_directories' && ret=0
}

_git-patch-id () {
  _message 'no arguments allowed; accepts patch on standard input'
}

_git-request-pull () {
  _arguments \
    ':start commit:__git_revisions' \
    ':url:_urls' \
    ':end commit:__git_revisions'
}

# TODO: do we want this?
#_git-rev-parse () {
#}

_git-send-email () {
  _arguments \
    '(--no-chain-reply-to)--chain-reply-to[each email will be sent as a reply to the previous one sent]' \
    '(--chain-reply-to)--no-chain-reply-to[all emails after the first will be sent as replies to the first one]' \
    '--compose[use $EDITOR to edit an introductory message for the patch series]' \
    '--from[specify the sender of the emails]' \
    '--in-reply-to[specify the contents of the first In-Reply-To header]' \
    '--smtp-server[specify the outgoing smtp server]:smtp server:_hosts' \
    '--subject[specify the initial subject of the email thread]' \
    '--to[specify the primary recipient of the emails]'
    ':file:_files' && ret=0
}

_git-stripspace () {
  _message 'no arguments allowed; accepts input file on standard input'
}

# ---

__git_guard () {
  typeset -A opts

  zparseopts -K -D -A opts M: J: V: 1 2 n F: X:

  [[ "$PREFIX$SUFFIX" != $~1 ]] && return 1

  if (( $+opts[-X] )); then
    _message -r $opts[-X]
  else
    _message -e $2
  fi

  [[ -n "$PREFIX$SUFFIX" ]]
}

__git_objects () {
  __git_guard $* "[[:xdigit:]]#" "object"
}

__git_trees () {
  __git_guard $* "[[:xdigit:]]#" "tree"
}

__git_tree_ishs () {
  __git_guard $* "[[:xdigit:]]#" "tree-ish"
}

__git_blobs () {
  _git_guard $* "[[:xdigit:]]#" 'blob id'
}

__git_stages () {
  __git_guard $* "[[:digit:]]#" 'stage'
}

__git_files () {
  local expl files

  files=("${(@f)$(git-ls-files 2>/dev/null)}")
  if (( $? == 0 )); then
    _wanted files expl 'index file' _multi_parts $@ - / files
  else
    _message 'not a git repository'
  fi
}

__git_tree_files () {
  local expl tree_files

  tree_files=(${"${(@f)$(git-ls-tree -r $@[-1] 2>/dev/null)}"#*$'\t'})
  if (( $? == 0 )); then
    _wanted files expl 'tree file' _multi_parts $@[1,-2] - / tree_files
  else
    _message 'not a git repository'
  fi
}

# TODO: deal with things that __git_heads and __git_tags has in common (i.e.,
# if both exists, they need to be completed to heads/x and tags/x.
__git_commits () {
  _alternative \
    'heads::__git_heads' \
    'tags::__git_tags'
}

# TODO: deal with prefixes and suffixes listed in git-rev-parse
__git_revisions () {
  __git_commits $*
}

__git_commits2 () {
  compset -P '\\\^'
  __git_commits
}

# FIXME: these should be imported from _ssh
# TODO: this should take -/ to only get directories
_remote_files () {
  # There should be coloring based on all the different ls -F classifiers.
  local expl rempat remfiles remdispf remdispd args suf ret=1

  if zstyle -T ":completion:${curcontext}:files" remote-access; then
    zparseopts -D -E -a args p: 1 2 4 6 F:
    if [[ -z $QIPREFIX ]]
    then rempat="${PREFIX%%[^./][^/]#}\*"
    else rempat="${(q)PREFIX%%[^./][^/]#}\*"
    fi
    remfiles=(${(M)${(f)"$(_call_program files ssh $args -a -x ${IPREFIX%:} ls -d1FL "$rempat" 2>/dev/null)"}%%[^/]#(|/)})
    compset -P '*/'
    compset -S '/*' || suf='remote file'

#    remdispf=(${remfiles:#*/})
    remdispd=(${(M)remfiles:#*/})

    _tags files
    while _tags; do
      while _next_label files expl ${suf:-remote directory}; do
#        [[ -n $suf ]] && compadd "$@" "$expl[@]" -d remdispf \
#	    ${(q)remdispf%[*=@|]} && ret=0 
	compadd ${suf:+-S/} "$@" "$expl[@]" -d remdispd \
	    ${(q)remdispd%/} && ret=0
      done
      (( ret )) || return 0
    done
    return ret
  else
    _message -e remote-files 'remote file'
  fi
}

__git_remote_repository () {
  local service

  service= _ssh

  if compset -P '*:'; then
    _remote_files
  else
    _alternative \
      'directories::_directories' \
      'hosts:host:_ssh_hosts -S:'
  fi
}

# should also be $GIT_DIR/remotes/origin
__git_any_repositories () {
  _alternative \
    'files::_files' \
    'remote repositories::__git_remote_repository'
}

__git_ref_specs () {
  if compset -P '*:'; then
    __git_heads
  else
    compset -P '+'
    if compset -S ':*'; then
      __git_heads
    else
      __git_heads -S ':'
    fi
  fi
}

__git_signoff_file () {
  _alternative \
    'signoffs:signoff:(yes true me please)' \
    'files:signoff file:_files'
}

__git_tag_ids () {
}

__git_heads_or_tags () {
  local expl
  typeset -a refs opts
  typeset -A ours

  zparseopts -K -D -a opts S: M: J: V: 1 2 n F: X: P:=ours T:=ours

  (( $+ours[-P] )) || ours[-P]=./.

  refs=(${${"${(@f)$(git ls-remote --$ours[-T] $ours[-P] 2>/dev/null)}"#*$'\t'}#refs/$ours[-T]/})
  if (( $? == 0 )); then
    _wanted $ours[-T] expl $ours[-T] compadd $opts - $refs
  else
    _message 'not a git repository'
  fi
}

__git_heads () {
  __git_heads_or_tags $* -T heads && ret=0
}

__git_tags () {
  __git_heads_or_tags $* -T tags && ret=0
}

# TODO: depending on what options are on the command-line already, complete
# only tags or heads
# TODO: perhaps caching is unnecessary.  usually won’t contain that much data
# TODO: perhaps provide alternative here for both heads and tags (and use
# __git_heads and __git_tags)
# TODO: instead of "./.", we should be looking in the repository specified as
# an argument to the command (but default to "./." I suppose (why not "."?))
__git_references () {
#  _alternative \
#    'heads::__git_heads' \
#    'tags::__git_tags' && ret=0
  local expl

  # TODO: deal with GIT_DIR
  if [[ $_git_refs_cache_pwd != $PWD ]]; then
    _git_refs_cache=(${${"${(@f)$(git ls-remote ./. 2>/dev/null)}"#*$'\t'}#refs/(heads|tags)/})
    _git_refs_cache_pwd=$PWD
  fi

  if (( $? == 0 )); then
    _wanted references expl 'references' compadd - $_git_refs_cache
  else
    _message 'not a git repository'
  fi
}

__git_local_references () {
  local expl

  if [[ $_git_local_refs_cache_pwd != $PWD ]]; then
    _git_local_refs_cache=(${${"${(@f)$(git ls-remote ./. 2>/dev/null)}"#*$'\t'}#refs/})
    _git_local_refs_cache_pwd=$PWD
  fi

  if (( $? == 0 )); then
    _wanted references expl 'references' compadd - $_git_local_refs_cache
  else
    _message 'not a git repository'
  fi
}

# ---

__git_is_indexed () {
  [[ -n $(git ls-files $REPLY) ]]
}
debug log:

solving 7b76d5a ...
found 7b76d5a in https://git.vuxu.org/mirror/zsh/

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).