@@ -73,14 +73,17 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
7373 struct object_info oi = OBJECT_INFO_INIT ;
7474 struct strbuf sb = STRBUF_INIT ;
7575 unsigned flags = OBJECT_INFO_LOOKUP_REPLACE ;
76+ unsigned get_oid_flags = GET_OID_RECORD_PATH | GET_OID_ONLY_TO_DIE ;
7677 const char * path = force_path ;
78+ const int opt_cw = (opt == 'c' || opt == 'w' );
79+ if (!path && opt_cw )
80+ get_oid_flags |= GET_OID_REQUIRE_PATH ;
7781
7882 if (unknown_type )
7983 flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE ;
8084
81- if (get_oid_with_context (the_repository , obj_name ,
82- GET_OID_RECORD_PATH ,
83- & oid , & obj_context ))
85+ if (get_oid_with_context (the_repository , obj_name , get_oid_flags , & oid ,
86+ & obj_context ))
8487 die ("Not a valid object name %s" , obj_name );
8588
8689 if (!path )
@@ -112,20 +115,13 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
112115 return !has_object_file (& oid );
113116
114117 case 'w' :
115- if (!path )
116- die ("git cat-file --filters %s: <object> must be "
117- "<sha1:path>" , obj_name );
118118
119119 if (filter_object (path , obj_context .mode ,
120120 & oid , & buf , & size ))
121121 return -1 ;
122122 break ;
123123
124124 case 'c' :
125- if (!path )
126- die ("git cat-file --textconv %s: <object> must be <sha1:path>" ,
127- obj_name );
128-
129125 if (textconv_object (the_repository , path , obj_context .mode ,
130126 & oid , 1 , & buf , & size ))
131127 break ;
@@ -618,12 +614,6 @@ static int batch_objects(struct batch_options *opt)
618614 return retval ;
619615}
620616
621- static const char * const cat_file_usage [] = {
622- N_ ("git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e | -p | <type> | --textconv | --filters) [--path=<path>] <object>" ),
623- N_ ("git cat-file (--batch[=<format>] | --batch-check[=<format>]) [--follow-symlinks] [--textconv | --filters]" ),
624- NULL
625- };
626-
627617static int git_cat_file_config (const char * var , const char * value , void * cb )
628618{
629619 if (userdiff_config (var , value ) < 0 )
@@ -654,90 +644,138 @@ static int batch_option_callback(const struct option *opt,
654644int cmd_cat_file (int argc , const char * * argv , const char * prefix )
655645{
656646 int opt = 0 ;
647+ int opt_cw = 0 ;
648+ int opt_epts = 0 ;
657649 const char * exp_type = NULL , * obj_name = NULL ;
658650 struct batch_options batch = {0 };
659651 int unknown_type = 0 ;
660652
653+ const char * const usage [] = {
654+ N_ ("git cat-file <type> <object>" ),
655+ N_ ("git cat-file (-e | -p) <object>" ),
656+ N_ ("git cat-file (-t | -s) [--allow-unknown-type] <object>" ),
657+ N_ ("git cat-file (--batch | --batch-check) [--batch-all-objects]\n"
658+ " [--buffer] [--follow-symlinks] [--unordered]\n"
659+ " [--textconv | --filters]" ),
660+ N_ ("git cat-file (--textconv | --filters)\n"
661+ " [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]" ),
662+ NULL
663+ };
661664 const struct option options [] = {
662- OPT_GROUP (N_ ("<type> can be one of: blob, tree, commit, tag" )),
663- OPT_CMDMODE ('t' , NULL , & opt , N_ ("show object type" ), 't' ),
664- OPT_CMDMODE ('s' , NULL , & opt , N_ ("show object size" ), 's' ),
665+ /* Simple queries */
666+ OPT_GROUP (N_ ("Check object existence or emit object contents" )),
665667 OPT_CMDMODE ('e' , NULL , & opt ,
666- N_ ("exit with zero when there's no error" ), 'e' ),
667- OPT_CMDMODE ('p' , NULL , & opt , N_ ("pretty-print object's content" ), 'p' ),
668- OPT_CMDMODE (0 , "textconv" , & opt ,
669- N_ ("for blob objects, run textconv on object's content" ), 'c' ),
670- OPT_CMDMODE (0 , "filters" , & opt ,
671- N_ ("for blob objects, run filters on object's content" ), 'w' ),
672- OPT_STRING (0 , "path" , & force_path , N_ ("blob" ),
673- N_ ("use a specific path for --textconv/--filters" )),
668+ N_ ("check if <object> exists" ), 'e' ),
669+ OPT_CMDMODE ('p' , NULL , & opt , N_ ("pretty-print <object> content" ), 'p' ),
670+
671+ OPT_GROUP (N_ ("Emit [broken] object attributes" )),
672+ OPT_CMDMODE ('t' , NULL , & opt , N_ ("show object type (one of 'blob', 'tree', 'commit', 'tag', ...)" ), 't' ),
673+ OPT_CMDMODE ('s' , NULL , & opt , N_ ("show object size" ), 's' ),
674674 OPT_BOOL (0 , "allow-unknown-type" , & unknown_type ,
675675 N_ ("allow -s and -t to work with broken/corrupt objects" )),
676- OPT_BOOL (0 , "buffer" , & batch .buffer_output , N_ ("buffer --batch output" )),
677- OPT_CALLBACK_F (0 , "batch" , & batch , "format" ,
678- N_ ("show info and content of objects fed from the standard input" ),
676+ /* Batch mode */
677+ OPT_GROUP (N_ ("Batch objects requested on stdin (or --batch-all-objects)" )),
678+ OPT_CALLBACK_F (0 , "batch" , & batch , N_ ("format" ),
679+ N_ ("show full <object> or <rev> contents" ),
679680 PARSE_OPT_OPTARG | PARSE_OPT_NONEG ,
680681 batch_option_callback ),
681- OPT_CALLBACK_F (0 , "batch-check" , & batch , "format" ,
682- N_ ("show info about objects fed from the standard input " ),
682+ OPT_CALLBACK_F (0 , "batch-check" , & batch , N_ ( "format" ) ,
683+ N_ ("like --batch, but don't emit <contents> " ),
683684 PARSE_OPT_OPTARG | PARSE_OPT_NONEG ,
684685 batch_option_callback ),
686+ OPT_CMDMODE (0 , "batch-all-objects" , & opt ,
687+ N_ ("with --batch[-check]: ignores stdin, batches all known objects" ), 'b' ),
688+ /* Batch-specific options */
689+ OPT_GROUP (N_ ("Change or optimize batch output" )),
690+ OPT_BOOL (0 , "buffer" , & batch .buffer_output , N_ ("buffer --batch output" )),
685691 OPT_BOOL (0 , "follow-symlinks" , & batch .follow_symlinks ,
686- N_ ("follow in-tree symlinks (used with --batch or --batch-check)" )),
687- OPT_BOOL (0 , "batch-all-objects" , & batch .all_objects ,
688- N_ ("show all objects with --batch or --batch-check" )),
692+ N_ ("follow in-tree symlinks" )),
689693 OPT_BOOL (0 , "unordered" , & batch .unordered ,
690- N_ ("do not order --batch-all-objects output" )),
694+ N_ ("do not order objects before emitting them" )),
695+ /* Textconv options, stand-ole*/
696+ OPT_GROUP (N_ ("Emit object (blob or tree) with conversion or filter (stand-alone, or with batch)" )),
697+ OPT_CMDMODE (0 , "textconv" , & opt ,
698+ N_ ("run textconv on object's content" ), 'c' ),
699+ OPT_CMDMODE (0 , "filters" , & opt ,
700+ N_ ("run filters on object's content" ), 'w' ),
701+ OPT_STRING (0 , "path" , & force_path , N_ ("blob|tree" ),
702+ N_ ("use a <path> for (--textconv | --filters); Not with 'batch'" )),
691703 OPT_END ()
692704 };
693705
694706 git_config (git_cat_file_config , NULL );
695707
696708 batch .buffer_output = -1 ;
697- argc = parse_options (argc , argv , prefix , options , cat_file_usage , 0 );
698-
699- if (opt ) {
700- if (batch .enabled && (opt == 'c' || opt == 'w' ))
701- batch .cmdmode = opt ;
702- else if (argc == 1 )
703- obj_name = argv [0 ];
704- else
705- usage_with_options (cat_file_usage , options );
706- }
707- if (!opt && !batch .enabled ) {
708- if (argc == 2 ) {
709- exp_type = argv [0 ];
710- obj_name = argv [1 ];
711- } else
712- usage_with_options (cat_file_usage , options );
713- }
714- if (batch .enabled ) {
715- if (batch .cmdmode != opt || argc )
716- usage_with_options (cat_file_usage , options );
717- if (batch .cmdmode && batch .all_objects )
718- die ("--batch-all-objects cannot be combined with "
719- "--textconv nor with --filters" );
720- }
721709
722- if (( batch . follow_symlinks || batch . all_objects ) && ! batch . enabled ) {
723- usage_with_options ( cat_file_usage , options );
724- }
710+ argc = parse_options ( argc , argv , prefix , options , usage , 0 );
711+ opt_cw = ( opt == 'c' || opt == 'w' );
712+ opt_epts = ( opt == 'e' || opt == 'p' || opt == 't' || opt == 's' );
725713
726- if (force_path && opt != 'c' && opt != 'w' ) {
727- error ("--path=<path> needs --textconv or --filters" );
728- usage_with_options (cat_file_usage , options );
729- }
714+ /* --batch-all-objects? */
715+ if (opt == 'b' )
716+ batch .all_objects = 1 ;
730717
731- if (force_path && batch .enabled ) {
732- error ("options '--path=<path>' and '--batch' cannot be used together" );
733- usage_with_options (cat_file_usage , options );
734- }
718+ /* Option compatibility */
719+ if (force_path && !opt_cw )
720+ usage_msg_optf (_ ("'%s=<%s>' needs '%s' or '%s'" ),
721+ usage , options ,
722+ "--path" , _ ("path|tree-ish" ), "--filters" ,
723+ "--textconv" );
735724
725+ /* Option compatibility with batch mode */
726+ if (batch .enabled )
727+ ;
728+ else if (batch .follow_symlinks )
729+ usage_msg_optf (_ ("'%s' requires a batch mode" ), usage , options ,
730+ "--follow-symlinks" );
731+ else if (batch .buffer_output >= 0 )
732+ usage_msg_optf (_ ("'%s' requires a batch mode" ), usage , options ,
733+ "--buffer" );
734+ else if (batch .all_objects )
735+ usage_msg_optf (_ ("'%s' requires a batch mode" ), usage , options ,
736+ "--batch-all-objects" );
737+
738+ /* Batch defaults */
736739 if (batch .buffer_output < 0 )
737740 batch .buffer_output = batch .all_objects ;
738741
739- if (batch .enabled )
742+ /* Return early if we're in batch mode? */
743+ if (batch .enabled ) {
744+ if (opt_cw )
745+ batch .cmdmode = opt ;
746+ else if (opt && opt != 'b' )
747+ usage_msg_optf (_ ("'-%c' is incompatible with batch mode" ),
748+ usage , options , opt );
749+ else if (argc )
750+ usage_msg_opt (_ ("batch modes take no arguments" ), usage ,
751+ options );
752+
740753 return batch_objects (& batch );
754+ }
755+
756+ if (opt ) {
757+ if (!argc && opt == 'c' )
758+ usage_msg_optf (_ ("<rev> required with '%s'" ),
759+ usage , options , "--textconv" );
760+ else if (!argc && opt == 'w' )
761+ usage_msg_optf (_ ("<rev> required with '%s'" ),
762+ usage , options , "--filters" );
763+ else if (!argc && opt_epts )
764+ usage_msg_optf (_ ("<object> required with '-%c'" ),
765+ usage , options , opt );
766+ else if (argc == 1 )
767+ obj_name = argv [0 ];
768+ else
769+ usage_msg_opt (_ ("too many arguments" ), usage , options );
770+ } else if (!argc ) {
771+ usage_with_options (usage , options );
772+ } else if (argc != 2 ) {
773+ usage_msg_optf (_ ("only two arguments allowed in <type> <object> mode, not %d" ),
774+ usage , options , argc );
775+ } else if (argc ) {
776+ exp_type = argv [0 ];
777+ obj_name = argv [1 ];
778+ }
741779
742780 if (unknown_type && opt != 't' && opt != 's' )
743781 die ("git cat-file --allow-unknown-type: use with -s or -t" );
0 commit comments