@@ -48,6 +48,10 @@ struct checkout_opts {
48
48
const char * prefix ;
49
49
struct pathspec pathspec ;
50
50
struct tree * source_tree ;
51
+
52
+ const char * new_worktree ;
53
+ const char * * saved_argv ;
54
+ int new_worktree_mode ;
51
55
};
52
56
53
57
static int post_checkout_hook (struct commit * old , struct commit * new ,
@@ -249,6 +253,9 @@ static int checkout_paths(const struct checkout_opts *opts,
249
253
die (_ ("Cannot update paths and switch to branch '%s' at the same time." ),
250
254
opts -> new_branch );
251
255
256
+ if (opts -> new_worktree )
257
+ die (_ ("'%s' cannot be used with updating paths" ), "--to" );
258
+
252
259
if (opts -> patch_mode )
253
260
return run_add_interactive (revision , "--patch=checkout" ,
254
261
& opts -> pathspec );
@@ -484,7 +491,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
484
491
topts .dir -> flags |= DIR_SHOW_IGNORED ;
485
492
setup_standard_excludes (topts .dir );
486
493
}
487
- tree = parse_tree_indirect (old -> commit ?
494
+ tree = parse_tree_indirect (old -> commit && ! opts -> new_worktree_mode ?
488
495
old -> commit -> object .sha1 :
489
496
EMPTY_TREE_SHA1_BIN );
490
497
init_tree_desc (& trees [0 ], tree -> buffer , tree -> size );
@@ -800,7 +807,8 @@ static int switch_branches(const struct checkout_opts *opts,
800
807
return ret ;
801
808
}
802
809
803
- if (!opts -> quiet && !old .path && old .commit && new -> commit != old .commit )
810
+ if (!opts -> quiet && !old .path && old .commit &&
811
+ new -> commit != old .commit && !opts -> new_worktree_mode )
804
812
orphaned_commit_warning (old .commit , new -> commit );
805
813
806
814
update_refs_for_switch (opts , & old , new );
@@ -810,6 +818,76 @@ static int switch_branches(const struct checkout_opts *opts,
810
818
return ret || writeout_error ;
811
819
}
812
820
821
+ static int prepare_linked_checkout (const struct checkout_opts * opts ,
822
+ struct branch_info * new )
823
+ {
824
+ struct strbuf sb_git = STRBUF_INIT , sb_repo = STRBUF_INIT ;
825
+ struct strbuf sb = STRBUF_INIT ;
826
+ const char * path = opts -> new_worktree , * name ;
827
+ struct stat st ;
828
+ struct child_process cp ;
829
+ int counter = 0 , len ;
830
+
831
+ if (!new -> commit )
832
+ die (_ ("no branch specified" ));
833
+ if (file_exists (path ))
834
+ die (_ ("'%s' already exists" ), path );
835
+
836
+ len = strlen (path );
837
+ while (len && is_dir_sep (path [len - 1 ]))
838
+ len -- ;
839
+
840
+ for (name = path + len - 1 ; name > path ; name -- )
841
+ if (is_dir_sep (* name )) {
842
+ name ++ ;
843
+ break ;
844
+ }
845
+ strbuf_addstr (& sb_repo ,
846
+ git_path ("worktrees/%.*s" , (int )(path + len - name ), name ));
847
+ len = sb_repo .len ;
848
+ if (safe_create_leading_directories_const (sb_repo .buf ))
849
+ die_errno (_ ("could not create leading directories of '%s'" ),
850
+ sb_repo .buf );
851
+ while (!stat (sb_repo .buf , & st )) {
852
+ counter ++ ;
853
+ strbuf_setlen (& sb_repo , len );
854
+ strbuf_addf (& sb_repo , "%d" , counter );
855
+ }
856
+ name = strrchr (sb_repo .buf , '/' ) + 1 ;
857
+ if (mkdir (sb_repo .buf , 0777 ))
858
+ die_errno (_ ("could not create directory of '%s'" ), sb_repo .buf );
859
+
860
+ strbuf_addf (& sb_git , "%s/.git" , path );
861
+ if (safe_create_leading_directories_const (sb_git .buf ))
862
+ die_errno (_ ("could not create leading directories of '%s'" ),
863
+ sb_git .buf );
864
+
865
+ write_file (sb_git .buf , 1 , "gitdir: %s/worktrees/%s\n" ,
866
+ real_path (get_git_common_dir ()), name );
867
+ /*
868
+ * This is to keep resolve_ref() happy. We need a valid HEAD
869
+ * or is_git_directory() will reject the directory. Any valid
870
+ * value would do because this value will be ignored and
871
+ * replaced at the next (real) checkout.
872
+ */
873
+ strbuf_addf (& sb , "%s/HEAD" , sb_repo .buf );
874
+ write_file (sb .buf , 1 , "%s\n" , sha1_to_hex (new -> commit -> object .sha1 ));
875
+ strbuf_reset (& sb );
876
+ strbuf_addf (& sb , "%s/commondir" , sb_repo .buf );
877
+ write_file (sb .buf , 1 , "../..\n" );
878
+
879
+ if (!opts -> quiet )
880
+ fprintf_ln (stderr , _ ("Enter %s (identifier %s)" ), path , name );
881
+
882
+ setenv ("GIT_CHECKOUT_NEW_WORKTREE" , "1" , 1 );
883
+ setenv (GIT_DIR_ENVIRONMENT , sb_git .buf , 1 );
884
+ setenv (GIT_WORK_TREE_ENVIRONMENT , path , 1 );
885
+ memset (& cp , 0 , sizeof (cp ));
886
+ cp .git_cmd = 1 ;
887
+ cp .argv = opts -> saved_argv ;
888
+ return run_command (& cp );
889
+ }
890
+
813
891
static int git_checkout_config (const char * var , const char * value , void * cb )
814
892
{
815
893
if (!strcmp (var , "diff.ignoresubmodules" )) {
@@ -1071,6 +1149,9 @@ static int checkout_branch(struct checkout_opts *opts,
1071
1149
die (_ ("Cannot switch branch to a non-commit '%s'" ),
1072
1150
new -> name );
1073
1151
1152
+ if (opts -> new_worktree )
1153
+ return prepare_linked_checkout (opts , new );
1154
+
1074
1155
if (!new -> commit && opts -> new_branch ) {
1075
1156
unsigned char rev [20 ];
1076
1157
int flag ;
@@ -1113,6 +1194,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1113
1194
N_ ("do not limit pathspecs to sparse entries only" )),
1114
1195
OPT_HIDDEN_BOOL (0 , "guess" , & dwim_new_local_branch ,
1115
1196
N_ ("second guess 'git checkout no-such-branch'" )),
1197
+ OPT_FILENAME (0 , "to" , & opts .new_worktree ,
1198
+ N_ ("check a branch out in a separate working directory" )),
1116
1199
OPT_END (),
1117
1200
};
1118
1201
@@ -1121,6 +1204,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1121
1204
opts .overwrite_ignore = 1 ;
1122
1205
opts .prefix = prefix ;
1123
1206
1207
+ opts .saved_argv = xmalloc (sizeof (const char * ) * (argc + 2 ));
1208
+ memcpy (opts .saved_argv , argv , sizeof (const char * ) * (argc + 1 ));
1209
+
1124
1210
gitmodules_config ();
1125
1211
git_config (git_checkout_config , & opts );
1126
1212
@@ -1129,6 +1215,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1129
1215
argc = parse_options (argc , argv , prefix , options , checkout_usage ,
1130
1216
PARSE_OPT_KEEP_DASHDASH );
1131
1217
1218
+ /* recursive execution from checkout_new_worktree() */
1219
+ opts .new_worktree_mode = getenv ("GIT_CHECKOUT_NEW_WORKTREE" ) != NULL ;
1220
+ if (opts .new_worktree_mode )
1221
+ opts .new_worktree = NULL ;
1222
+
1132
1223
if (conflict_style ) {
1133
1224
opts .merge = 1 ; /* implied */
1134
1225
git_xmerge_config ("merge.conflictstyle" , conflict_style , NULL );
0 commit comments