27
27
#include "wt-status.h"
28
28
#include "xdiff-interface.h"
29
29
30
+ static int checkout_optimize_new_branch ;
31
+
30
32
static const char * const checkout_usage [] = {
31
33
N_ ("git checkout [<options>] <branch>" ),
32
34
N_ ("git checkout [<options>] [<branch>] -- <file>..." ),
@@ -71,6 +73,11 @@ struct checkout_opts {
71
73
const char * ignore_unmerged_opt ;
72
74
int ignore_unmerged ;
73
75
76
+ /*
77
+ * If new checkout options are added, skip_merge_working_tree
78
+ * should be updated accordingly.
79
+ */
80
+
74
81
const char * new_branch ;
75
82
const char * new_branch_force ;
76
83
const char * new_orphan_branch ;
@@ -637,6 +644,112 @@ static void setup_branch_path(struct branch_info *branch)
637
644
branch -> path = strbuf_detach (& buf , NULL );
638
645
}
639
646
647
+ /*
648
+ * Skip merging the trees, updating the index and working directory if and
649
+ * only if we are creating a new branch via "git checkout -b <new_branch>."
650
+ */
651
+ static int skip_merge_working_tree (const struct checkout_opts * opts ,
652
+ const struct branch_info * old_branch_info ,
653
+ const struct branch_info * new_branch_info )
654
+ {
655
+ /*
656
+ * Do the merge if sparse checkout is on and the user has not opted in
657
+ * to the optimized behavior
658
+ */
659
+ if (core_apply_sparse_checkout && !checkout_optimize_new_branch )
660
+ return 0 ;
661
+
662
+ /*
663
+ * We must do the merge if we are actually moving to a new commit.
664
+ */
665
+ if (!old_branch_info -> commit || !new_branch_info -> commit ||
666
+ !oideq (& old_branch_info -> commit -> object .oid ,
667
+ & new_branch_info -> commit -> object .oid ))
668
+ return 0 ;
669
+
670
+ /*
671
+ * opts->patch_mode cannot be used with switching branches so is
672
+ * not tested here
673
+ */
674
+
675
+ /*
676
+ * opts->quiet only impacts output so doesn't require a merge
677
+ */
678
+
679
+ /*
680
+ * Honor the explicit request for a three-way merge or to throw away
681
+ * local changes
682
+ */
683
+ if (opts -> merge || opts -> force )
684
+ return 0 ;
685
+
686
+ /*
687
+ * --detach is documented as "updating the index and the files in the
688
+ * working tree" but this optimization skips those steps so fall through
689
+ * to the regular code path.
690
+ */
691
+ if (opts -> force_detach )
692
+ return 0 ;
693
+
694
+ /*
695
+ * opts->writeout_stage cannot be used with switching branches so is
696
+ * not tested here
697
+ */
698
+
699
+ /*
700
+ * Honor the explicit ignore requests
701
+ */
702
+ if (!opts -> overwrite_ignore || opts -> ignore_skipworktree ||
703
+ opts -> ignore_other_worktrees )
704
+ return 0 ;
705
+
706
+ /*
707
+ * opts->show_progress only impacts output so doesn't require a merge
708
+ */
709
+
710
+ /*
711
+ * opts->overlay_mode cannot be used with switching branches so is
712
+ * not tested here
713
+ */
714
+
715
+ /*
716
+ * If we aren't creating a new branch any changes or updates will
717
+ * happen in the existing branch. Since that could only be updating
718
+ * the index and working directory, we don't want to skip those steps
719
+ * or we've defeated any purpose in running the command.
720
+ */
721
+ if (!opts -> new_branch )
722
+ return 0 ;
723
+
724
+ /*
725
+ * new_branch_force is defined to "create/reset and checkout a branch"
726
+ * so needs to go through the merge to do the reset
727
+ */
728
+ if (opts -> new_branch_force )
729
+ return 0 ;
730
+
731
+ /*
732
+ * A new orphaned branch requrires the index and the working tree to be
733
+ * adjusted to <start_point>
734
+ */
735
+ if (opts -> new_orphan_branch )
736
+ return 0 ;
737
+
738
+ /*
739
+ * Remaining variables are not checkout options but used to track state
740
+ */
741
+
742
+ /*
743
+ * Do the merge if this is the initial checkout. We cannot use
744
+ * is_cache_unborn() here because the index hasn't been loaded yet
745
+ * so cache_nr and timestamp.sec are always zero.
746
+ */
747
+ if (!file_exists (get_index_file ()))
748
+ return 0 ;
749
+
750
+ return 1 ;
751
+ }
752
+
640
753
static int merge_working_tree (const struct checkout_opts * opts ,
641
754
struct branch_info * old_branch_info ,
642
755
struct branch_info * new_branch_info ,
@@ -1020,7 +1133,6 @@ static int switch_branches(const struct checkout_opts *opts,
1020
1133
void * path_to_free ;
1021
1134
struct object_id rev ;
1022
1135
int flag , writeout_error = 0 ;
1023
- int do_merge = 1 ;
1024
1136
1025
1137
trace2_cmd_mode ("branch" );
1026
1138
@@ -1039,7 +1151,6 @@ static int switch_branches(const struct checkout_opts *opts,
1039
1151
BUG ("'switch --orphan' should never accept a commit as starting point" );
1040
1152
new_branch_info -> commit = NULL ;
1041
1153
new_branch_info -> name = "(empty)" ;
1042
- do_merge = 1 ;
1043
1154
}
1044
1155
1045
1156
if (!new_branch_info -> name ) {
@@ -1048,12 +1159,16 @@ static int switch_branches(const struct checkout_opts *opts,
1048
1159
if (!new_branch_info -> commit )
1049
1160
die (_ ("You are on a branch yet to be born" ));
1050
1161
parse_commit_or_die (new_branch_info -> commit );
1051
-
1052
- if (opts -> only_merge_on_switching_branches )
1053
- do_merge = 0 ;
1054
1162
}
1055
1163
1056
- if (do_merge ) {
1164
+ /* optimize the "checkout -b <new_branch> path */
1165
+ if (skip_merge_working_tree (opts , & old_branch_info , new_branch_info )) {
1166
+ if (!checkout_optimize_new_branch && !opts -> quiet ) {
1167
+ if (read_cache_preload (NULL ) < 0 )
1168
+ return error (_ ("index file corrupt" ));
1169
+ show_local_changes (& new_branch_info -> commit -> object , & opts -> diff_options );
1170
+ }
1171
+ } else {
1057
1172
ret = merge_working_tree (opts , & old_branch_info , new_branch_info , & writeout_error );
1058
1173
if (ret ) {
1059
1174
free (path_to_free );
@@ -1073,6 +1188,11 @@ static int switch_branches(const struct checkout_opts *opts,
1073
1188
1074
1189
static int git_checkout_config (const char * var , const char * value , void * cb )
1075
1190
{
1191
+ if (!strcmp (var , "checkout.optimizenewbranch" )) {
1192
+ checkout_optimize_new_branch = git_config_bool (var , value );
1193
+ return 0 ;
1194
+ }
1195
+
1076
1196
if (!strcmp (var , "diff.ignoresubmodules" )) {
1077
1197
struct checkout_opts * opts = cb ;
1078
1198
handle_ignore_submodules_arg (& opts -> diff_options , value );
@@ -1747,7 +1867,6 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
1747
1867
opts .accept_ref = 1 ;
1748
1868
opts .accept_pathspec = 0 ;
1749
1869
opts .switch_branch_doing_nothing_is_ok = 0 ;
1750
- opts .only_merge_on_switching_branches = 1 ;
1751
1870
opts .implicit_detach = 0 ;
1752
1871
opts .can_switch_when_in_progress = 0 ;
1753
1872
opts .orphan_from_empty_tree = 1 ;
0 commit comments