18
18
static const char * empty_base = "" ;
19
19
20
20
static char const * const builtin_sparse_checkout_usage [] = {
21
- N_ ("git sparse-checkout (init|list|set|disable) <options>" ),
21
+ N_ ("git sparse-checkout (init|list|set|add| disable) <options>" ),
22
22
NULL
23
23
};
24
24
@@ -394,6 +394,9 @@ static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
394
394
395
395
strbuf_trim_trailing_dir_sep (line );
396
396
397
+ if (strbuf_normalize_path (line ))
398
+ die (_ ("could not normalize path %s" ), line -> buf );
399
+
397
400
if (!line -> len )
398
401
return ;
399
402
@@ -404,44 +407,24 @@ static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
404
407
}
405
408
406
409
static char const * const builtin_sparse_checkout_set_usage [] = {
407
- N_ ("git sparse-checkout set (--stdin | <patterns>)" ),
410
+ N_ ("git sparse-checkout ( set|add) (--stdin | <patterns>)" ),
408
411
NULL
409
412
};
410
413
411
414
static struct sparse_checkout_set_opts {
412
415
int use_stdin ;
413
416
} set_opts ;
414
417
415
- static int sparse_checkout_set (int argc , const char * * argv , const char * prefix )
418
+ static void add_patterns_from_input (struct pattern_list * pl ,
419
+ int argc , const char * * argv )
416
420
{
417
421
int i ;
418
- struct pattern_list pl ;
419
- int result ;
420
- int changed_config = 0 ;
421
-
422
- static struct option builtin_sparse_checkout_set_options [] = {
423
- OPT_BOOL (0 , "stdin" , & set_opts .use_stdin ,
424
- N_ ("read patterns from standard in" )),
425
- OPT_END (),
426
- };
427
-
428
- repo_read_index (the_repository );
429
- require_clean_work_tree (the_repository ,
430
- N_ ("set sparse-checkout patterns" ), NULL , 1 , 0 );
431
-
432
- memset (& pl , 0 , sizeof (pl ));
433
-
434
- argc = parse_options (argc , argv , prefix ,
435
- builtin_sparse_checkout_set_options ,
436
- builtin_sparse_checkout_set_usage ,
437
- PARSE_OPT_KEEP_UNKNOWN );
438
-
439
422
if (core_sparse_checkout_cone ) {
440
423
struct strbuf line = STRBUF_INIT ;
441
424
442
- hashmap_init (& pl . recursive_hashmap , pl_hashmap_cmp , NULL , 0 );
443
- hashmap_init (& pl . parent_hashmap , pl_hashmap_cmp , NULL , 0 );
444
- pl . use_cone_patterns = 1 ;
425
+ hashmap_init (& pl -> recursive_hashmap , pl_hashmap_cmp , NULL , 0 );
426
+ hashmap_init (& pl -> parent_hashmap , pl_hashmap_cmp , NULL , 0 );
427
+ pl -> use_cone_patterns = 1 ;
445
428
446
429
if (set_opts .use_stdin ) {
447
430
struct strbuf unquoted = STRBUF_INIT ;
@@ -455,15 +438,15 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
455
438
strbuf_swap (& unquoted , & line );
456
439
}
457
440
458
- strbuf_to_cone_pattern (& line , & pl );
441
+ strbuf_to_cone_pattern (& line , pl );
459
442
}
460
443
461
444
strbuf_release (& unquoted );
462
445
} else {
463
446
for (i = 0 ; i < argc ; i ++ ) {
464
447
strbuf_setlen (& line , 0 );
465
448
strbuf_addstr (& line , argv [i ]);
466
- strbuf_to_cone_pattern (& line , & pl );
449
+ strbuf_to_cone_pattern (& line , pl );
467
450
}
468
451
}
469
452
} else {
@@ -473,13 +456,84 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
473
456
while (!strbuf_getline (& line , stdin )) {
474
457
size_t len ;
475
458
char * buf = strbuf_detach (& line , & len );
476
- add_pattern (buf , empty_base , 0 , & pl , 0 );
459
+ add_pattern (buf , empty_base , 0 , pl , 0 );
477
460
}
478
461
} else {
479
462
for (i = 0 ; i < argc ; i ++ )
480
- add_pattern (argv [i ], empty_base , 0 , & pl , 0 );
463
+ add_pattern (argv [i ], empty_base , 0 , pl , 0 );
481
464
}
482
465
}
466
+ }
467
+
468
+ enum modify_type {
469
+ REPLACE ,
470
+ ADD ,
471
+ };
472
+
473
+ static void add_patterns_cone_mode (int argc , const char * * argv ,
474
+ struct pattern_list * pl )
475
+ {
476
+ struct strbuf buffer = STRBUF_INIT ;
477
+ struct pattern_entry * pe ;
478
+ struct hashmap_iter iter ;
479
+ struct pattern_list existing ;
480
+ char * sparse_filename = get_sparse_checkout_filename ();
481
+
482
+ add_patterns_from_input (pl , argc , argv );
483
+
484
+ memset (& existing , 0 , sizeof (existing ));
485
+ existing .use_cone_patterns = core_sparse_checkout_cone ;
486
+
487
+ if (add_patterns_from_file_to_list (sparse_filename , "" , 0 ,
488
+ & existing , NULL ))
489
+ die (_ ("unable to load existing sparse-checkout patterns" ));
490
+ free (sparse_filename );
491
+
492
+ hashmap_for_each_entry (& existing .recursive_hashmap , & iter , pe , ent ) {
493
+ if (!hashmap_contains_parent (& pl -> recursive_hashmap ,
494
+ pe -> pattern , & buffer ) ||
495
+ !hashmap_contains_parent (& pl -> parent_hashmap ,
496
+ pe -> pattern , & buffer )) {
497
+ strbuf_reset (& buffer );
498
+ strbuf_addstr (& buffer , pe -> pattern );
499
+ insert_recursive_pattern (pl , & buffer );
500
+ }
501
+ }
502
+
503
+ clear_pattern_list (& existing );
504
+ strbuf_release (& buffer );
505
+ }
506
+
507
+ static void add_patterns_literal (int argc , const char * * argv ,
508
+ struct pattern_list * pl )
509
+ {
510
+ char * sparse_filename = get_sparse_checkout_filename ();
511
+ if (add_patterns_from_file_to_list (sparse_filename , "" , 0 ,
512
+ pl , NULL ))
513
+ die (_ ("unable to load existing sparse-checkout patterns" ));
514
+ free (sparse_filename );
515
+ add_patterns_from_input (pl , argc , argv );
516
+ }
517
+
518
+ static int modify_pattern_list (int argc , const char * * argv , enum modify_type m )
519
+ {
520
+ int result ;
521
+ int changed_config = 0 ;
522
+ struct pattern_list pl ;
523
+ memset (& pl , 0 , sizeof (pl ));
524
+
525
+ switch (m ) {
526
+ case ADD :
527
+ if (core_sparse_checkout_cone )
528
+ add_patterns_cone_mode (argc , argv , & pl );
529
+ else
530
+ add_patterns_literal (argc , argv , & pl );
531
+ break ;
532
+
533
+ case REPLACE :
534
+ add_patterns_from_input (& pl , argc , argv );
535
+ break ;
536
+ }
483
537
484
538
if (!core_apply_sparse_checkout ) {
485
539
set_config (MODE_ALL_PATTERNS );
@@ -496,6 +550,27 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
496
550
return result ;
497
551
}
498
552
553
+ static int sparse_checkout_set (int argc , const char * * argv , const char * prefix ,
554
+ enum modify_type m )
555
+ {
556
+ static struct option builtin_sparse_checkout_set_options [] = {
557
+ OPT_BOOL (0 , "stdin" , & set_opts .use_stdin ,
558
+ N_ ("read patterns from standard in" )),
559
+ OPT_END (),
560
+ };
561
+
562
+ repo_read_index (the_repository );
563
+ require_clean_work_tree (the_repository ,
564
+ N_ ("set sparse-checkout patterns" ), NULL , 1 , 0 );
565
+
566
+ argc = parse_options (argc , argv , prefix ,
567
+ builtin_sparse_checkout_set_options ,
568
+ builtin_sparse_checkout_set_usage ,
569
+ PARSE_OPT_KEEP_UNKNOWN );
570
+
571
+ return modify_pattern_list (argc , argv , m );
572
+ }
573
+
499
574
static int sparse_checkout_disable (int argc , const char * * argv )
500
575
{
501
576
struct pattern_list pl ;
@@ -544,7 +619,9 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
544
619
if (!strcmp (argv [0 ], "init" ))
545
620
return sparse_checkout_init (argc , argv );
546
621
if (!strcmp (argv [0 ], "set" ))
547
- return sparse_checkout_set (argc , argv , prefix );
622
+ return sparse_checkout_set (argc , argv , prefix , REPLACE );
623
+ if (!strcmp (argv [0 ], "add" ))
624
+ return sparse_checkout_set (argc , argv , prefix , ADD );
548
625
if (!strcmp (argv [0 ], "disable" ))
549
626
return sparse_checkout_disable (argc , argv );
550
627
}
0 commit comments