@@ -194,6 +194,31 @@ static int stash_to_index(
194
194
return git_index_add (index , & entry );
195
195
}
196
196
197
+ static int stash_update_index_from_paths (
198
+ git_repository * repo ,
199
+ git_index * index ,
200
+ git_strarray * paths )
201
+ {
202
+ unsigned int status_flags ;
203
+ size_t i ;
204
+ int error = 0 ;
205
+
206
+ for (i = 0 ; i < paths -> count ; i ++ ) {
207
+ git_status_file (& status_flags , repo , paths -> strings [i ]);
208
+
209
+ if (status_flags & (GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_DELETED )) {
210
+ if ((error = git_index_remove (index , paths -> strings [i ], 0 )) < 0 )
211
+ return error ;
212
+ }
213
+ else {
214
+ if ((error = stash_to_index (repo , index , paths -> strings [i ])) < 0 )
215
+ return error ;
216
+ }
217
+ }
218
+
219
+ return error ;
220
+ }
221
+
197
222
static int stash_update_index_from_diff (
198
223
git_repository * repo ,
199
224
git_index * index ,
@@ -576,6 +601,50 @@ static int ensure_there_are_changes_to_stash(git_repository *repo, uint32_t flag
576
601
return error ;
577
602
}
578
603
604
+ static int has_changes_cb (const char * path , unsigned int status , void * payload ) {
605
+ GIT_UNUSED (path );
606
+ GIT_UNUSED (status );
607
+ GIT_UNUSED (payload );
608
+
609
+ if (status == GIT_STATUS_CURRENT )
610
+ return GIT_ENOTFOUND ;
611
+
612
+ return 0 ;
613
+ }
614
+
615
+ static int ensure_there_are_changes_to_stash_paths (
616
+ git_repository * repo ,
617
+ uint32_t flags ,
618
+ git_strarray * paths )
619
+ {
620
+ int error ;
621
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT ;
622
+
623
+ opts .show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR ;
624
+ opts .flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES
625
+ | GIT_STATUS_OPT_INCLUDE_UNMODIFIED
626
+ | GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH ;
627
+
628
+ if (flags & GIT_STASH_INCLUDE_UNTRACKED )
629
+ opts .flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED |
630
+ GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS ;
631
+
632
+ if (flags & GIT_STASH_INCLUDE_IGNORED )
633
+ opts .flags |= GIT_STATUS_OPT_INCLUDE_IGNORED |
634
+ GIT_STATUS_OPT_RECURSE_IGNORED_DIRS ;
635
+
636
+ git_strarray_copy (& opts .pathspec , paths );
637
+
638
+ error = git_status_foreach_ext (repo , & opts , has_changes_cb , NULL );
639
+
640
+ git_strarray_dispose (& opts .pathspec );
641
+
642
+ if (error == GIT_ENOTFOUND )
643
+ return create_error (GIT_ENOTFOUND , "one of the files does not have any changes to stash." );
644
+
645
+ return error ;
646
+ }
647
+
579
648
static int reset_index_and_workdir (git_repository * repo , git_commit * commit , uint32_t flags )
580
649
{
581
650
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT ;
@@ -596,50 +665,87 @@ int git_stash_save(
596
665
const char * message ,
597
666
uint32_t flags )
598
667
{
599
- git_index * index = NULL ;
668
+ git_stash_save_options opts = GIT_STASH_SAVE_OPTIONS_INIT ;
669
+ opts .stasher = stasher ;
670
+ opts .message = message ;
671
+ opts .flags = flags ;
672
+ return git_stash_save_with_opts (out , repo , & opts );
673
+ }
674
+
675
+ int git_stash_save_with_opts (
676
+ git_oid * out , git_repository * repo , git_stash_save_options * opts )
677
+ {
678
+ git_index * index = NULL , * paths_index = NULL ;
600
679
git_commit * b_commit = NULL , * i_commit = NULL , * u_commit = NULL ;
601
680
git_buf msg = GIT_BUF_INIT ;
681
+ git_tree * tree = NULL ;
682
+ git_reference * head = NULL ;
602
683
int error ;
603
684
604
685
GIT_ASSERT_ARG (out );
605
686
GIT_ASSERT_ARG (repo );
606
- GIT_ASSERT_ARG (stasher );
607
687
608
688
if ((error = git_repository__ensure_not_bare (repo , "stash save" )) < 0 )
609
689
return error ;
610
690
611
691
if ((error = retrieve_base_commit_and_message (& b_commit , & msg , repo )) < 0 )
612
692
goto cleanup ;
613
693
614
- if ((error = ensure_there_are_changes_to_stash (repo , flags )) < 0 )
694
+ if (opts -> paths .count == 0 &&
695
+ (error = ensure_there_are_changes_to_stash (repo , opts -> flags )) < 0 )
696
+ goto cleanup ;
697
+ else if (opts -> paths .count > 0 &&
698
+ (error = ensure_there_are_changes_to_stash_paths (
699
+ repo , opts -> flags , & opts -> paths )) < 0 )
615
700
goto cleanup ;
616
701
617
702
if ((error = git_repository_index (& index , repo )) < 0 )
618
703
goto cleanup ;
619
704
620
- if ((error = commit_index (& i_commit , repo , index , stasher ,
621
- git_buf_cstr (& msg ), b_commit )) < 0 )
705
+ if ((error = commit_index (& i_commit , repo , index , opts -> stasher ,
706
+ git_buf_cstr (& msg ), b_commit )) < 0 )
622
707
goto cleanup ;
623
708
624
- if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED )) &&
625
- (error = commit_untracked (& u_commit , repo , stasher ,
626
- git_buf_cstr (& msg ), i_commit , flags )) < 0 )
709
+ if ((opts -> flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED )) &&
710
+ (error = commit_untracked (& u_commit , repo , opts -> stasher ,
711
+ git_buf_cstr (& msg ), i_commit , opts -> flags )) < 0 )
627
712
goto cleanup ;
628
713
629
- if ((error = prepare_worktree_commit_message (& msg , message )) < 0 )
714
+ if ((error = prepare_worktree_commit_message (& msg , opts -> message )) < 0 )
630
715
goto cleanup ;
631
716
632
- if ((error = commit_worktree (out , repo , stasher , git_buf_cstr (& msg ),
633
- i_commit , b_commit , u_commit )) < 0 )
634
- goto cleanup ;
717
+ if (opts -> paths .count == 0 ) {
718
+ if ((error = commit_worktree (out , repo , opts -> stasher , git_buf_cstr (& msg ),
719
+ i_commit , b_commit , u_commit )) < 0 )
720
+ goto cleanup ;
721
+ } else {
722
+ if ((error = git_index_new (& paths_index )) < 0 )
723
+ goto cleanup ;
724
+
725
+ if ((error = retrieve_head (& head , repo )) < 0 )
726
+ goto cleanup ;
727
+
728
+ if ((error = git_reference_peel ((git_object * * )& tree , head , GIT_OBJECT_TREE )) < 0 )
729
+ goto cleanup ;
730
+
731
+ if ((error = git_index_read_tree (paths_index , tree )) < 0 )
732
+ goto cleanup ;
733
+
734
+ if ((error = stash_update_index_from_paths (repo , paths_index , & opts -> paths )) < 0 )
735
+ goto cleanup ;
736
+
737
+ if ((error = build_stash_commit_from_index (out , repo , opts -> stasher , git_buf_cstr (& msg ),
738
+ i_commit , b_commit , u_commit , paths_index )) < 0 )
739
+ goto cleanup ;
740
+ }
635
741
636
742
git_buf_rtrim (& msg );
637
743
638
744
if ((error = update_reflog (out , repo , git_buf_cstr (& msg ))) < 0 )
639
745
goto cleanup ;
640
746
641
- if (( error = reset_index_and_workdir ( repo , ( flags & GIT_STASH_KEEP_INDEX ) ? i_commit : b_commit ,
642
- flags )) < 0 )
747
+ if (!( opts -> flags & GIT_STASH_KEEP_ALL ) && ( error = reset_index_and_workdir ( repo ,
748
+ ( opts -> flags & GIT_STASH_KEEP_INDEX ) ? i_commit : b_commit , opts -> flags )) < 0 )
643
749
goto cleanup ;
644
750
645
751
cleanup :
@@ -648,7 +754,10 @@ int git_stash_save(
648
754
git_commit_free (i_commit );
649
755
git_commit_free (b_commit );
650
756
git_commit_free (u_commit );
757
+ git_tree_free (tree );
758
+ git_reference_free (head );
651
759
git_index_free (index );
760
+ git_index_free (paths_index );
652
761
653
762
return error ;
654
763
}
@@ -833,6 +942,13 @@ int git_stash_apply_options_init(git_stash_apply_options *opts, unsigned int ver
833
942
return 0 ;
834
943
}
835
944
945
+ int git_stash_save_options_init (git_stash_save_options * opts , unsigned int version )
946
+ {
947
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE (
948
+ opts , version , git_stash_save_options , GIT_STASH_SAVE_OPTIONS_INIT );
949
+ return 0 ;
950
+ }
951
+
836
952
#ifndef GIT_DEPRECATE_HARD
837
953
int git_stash_apply_init_options (git_stash_apply_options * opts , unsigned int version )
838
954
{
0 commit comments