@@ -26,7 +26,8 @@ enum deny_action {
26
26
DENY_UNCONFIGURED ,
27
27
DENY_IGNORE ,
28
28
DENY_WARN ,
29
- DENY_REFUSE
29
+ DENY_REFUSE ,
30
+ DENY_UPDATE_INSTEAD
30
31
};
31
32
32
33
static int deny_deletes ;
@@ -76,6 +77,8 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
76
77
return DENY_WARN ;
77
78
if (!strcasecmp (value , "refuse" ))
78
79
return DENY_REFUSE ;
80
+ if (!strcasecmp (value , "updateinstead" ))
81
+ return DENY_UPDATE_INSTEAD ;
79
82
}
80
83
if (git_config_bool (var , value ))
81
84
return DENY_REFUSE ;
@@ -730,11 +733,89 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
730
733
return 0 ;
731
734
}
732
735
736
+ static const char * update_worktree (unsigned char * sha1 )
737
+ {
738
+ const char * update_refresh [] = {
739
+ "update-index" , "-q" , "--ignore-submodules" , "--refresh" , NULL
740
+ };
741
+ const char * diff_files [] = {
742
+ "diff-files" , "--quiet" , "--ignore-submodules" , "--" , NULL
743
+ };
744
+ const char * diff_index [] = {
745
+ "diff-index" , "--quiet" , "--cached" , "--ignore-submodules" ,
746
+ "HEAD" , "--" , NULL
747
+ };
748
+ const char * read_tree [] = {
749
+ "read-tree" , "-u" , "-m" , NULL , NULL
750
+ };
751
+ const char * work_tree = git_work_tree_cfg ? git_work_tree_cfg : ".." ;
752
+ struct argv_array env = ARGV_ARRAY_INIT ;
753
+ struct child_process child = CHILD_PROCESS_INIT ;
754
+
755
+ if (is_bare_repository ())
756
+ return "denyCurrentBranch = updateInstead needs a worktree" ;
757
+
758
+ argv_array_pushf (& env , "GIT_DIR=%s" , absolute_path (get_git_dir ()));
759
+
760
+ child .argv = update_refresh ;
761
+ child .env = env .argv ;
762
+ child .dir = work_tree ;
763
+ child .no_stdin = 1 ;
764
+ child .stdout_to_stderr = 1 ;
765
+ child .git_cmd = 1 ;
766
+ if (run_command (& child )) {
767
+ argv_array_clear (& env );
768
+ return "Up-to-date check failed" ;
769
+ }
770
+
771
+ /* run_command() does not clean up completely; reinitialize */
772
+ child_process_init (& child );
773
+ child .argv = diff_files ;
774
+ child .env = env .argv ;
775
+ child .dir = work_tree ;
776
+ child .no_stdin = 1 ;
777
+ child .stdout_to_stderr = 1 ;
778
+ child .git_cmd = 1 ;
779
+ if (run_command (& child )) {
780
+ argv_array_clear (& env );
781
+ return "Working directory has unstaged changes" ;
782
+ }
783
+
784
+ child_process_init (& child );
785
+ child .argv = diff_index ;
786
+ child .env = env .argv ;
787
+ child .no_stdin = 1 ;
788
+ child .no_stdout = 1 ;
789
+ child .stdout_to_stderr = 0 ;
790
+ child .git_cmd = 1 ;
791
+ if (run_command (& child )) {
792
+ argv_array_clear (& env );
793
+ return "Working directory has staged changes" ;
794
+ }
795
+
796
+ read_tree [3 ] = sha1_to_hex (sha1 );
797
+ child_process_init (& child );
798
+ child .argv = read_tree ;
799
+ child .env = env .argv ;
800
+ child .dir = work_tree ;
801
+ child .no_stdin = 1 ;
802
+ child .no_stdout = 1 ;
803
+ child .stdout_to_stderr = 0 ;
804
+ child .git_cmd = 1 ;
805
+ if (run_command (& child )) {
806
+ argv_array_clear (& env );
807
+ return "Could not update working tree to new HEAD" ;
808
+ }
809
+
810
+ argv_array_clear (& env );
811
+ return NULL ;
812
+ }
813
+
733
814
static const char * update (struct command * cmd , struct shallow_info * si )
734
815
{
735
816
const char * name = cmd -> ref_name ;
736
817
struct strbuf namespaced_name_buf = STRBUF_INIT ;
737
- const char * namespaced_name ;
818
+ const char * namespaced_name , * ret ;
738
819
unsigned char * old_sha1 = cmd -> old_sha1 ;
739
820
unsigned char * new_sha1 = cmd -> new_sha1 ;
740
821
@@ -760,6 +841,11 @@ static const char *update(struct command *cmd, struct shallow_info *si)
760
841
if (deny_current_branch == DENY_UNCONFIGURED )
761
842
refuse_unconfigured_deny ();
762
843
return "branch is currently checked out" ;
844
+ case DENY_UPDATE_INSTEAD :
845
+ ret = update_worktree (new_sha1 );
846
+ if (ret )
847
+ return ret ;
848
+ break ;
763
849
}
764
850
}
765
851
@@ -784,10 +870,13 @@ static const char *update(struct command *cmd, struct shallow_info *si)
784
870
break ;
785
871
case DENY_REFUSE :
786
872
case DENY_UNCONFIGURED :
873
+ case DENY_UPDATE_INSTEAD :
787
874
if (deny_delete_current == DENY_UNCONFIGURED )
788
875
refuse_unconfigured_deny_delete_current ();
789
876
rp_error ("refusing to delete the current branch: %s" , name );
790
877
return "deletion of the current branch prohibited" ;
878
+ default :
879
+ return "Invalid denyDeleteCurrent setting" ;
791
880
}
792
881
}
793
882
}
0 commit comments