@@ -48,6 +48,10 @@ struct checkout_opts {
4848 const char * prefix ;
4949 struct pathspec pathspec ;
5050 struct tree * source_tree ;
51+
52+ const char * new_worktree ;
53+ const char * * saved_argv ;
54+ int new_worktree_mode ;
5155};
5256
5357static int post_checkout_hook (struct commit * old , struct commit * new ,
@@ -249,6 +253,9 @@ static int checkout_paths(const struct checkout_opts *opts,
249253 die (_ ("Cannot update paths and switch to branch '%s' at the same time." ),
250254 opts -> new_branch );
251255
256+ if (opts -> new_worktree )
257+ die (_ ("'%s' cannot be used with updating paths" ), "--to" );
258+
252259 if (opts -> patch_mode )
253260 return run_add_interactive (revision , "--patch=checkout" ,
254261 & opts -> pathspec );
@@ -484,7 +491,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
484491 topts .dir -> flags |= DIR_SHOW_IGNORED ;
485492 setup_standard_excludes (topts .dir );
486493 }
487- tree = parse_tree_indirect (old -> commit ?
494+ tree = parse_tree_indirect (old -> commit && ! opts -> new_worktree_mode ?
488495 old -> commit -> object .sha1 :
489496 EMPTY_TREE_SHA1_BIN );
490497 init_tree_desc (& trees [0 ], tree -> buffer , tree -> size );
@@ -800,7 +807,8 @@ static int switch_branches(const struct checkout_opts *opts,
800807 return ret ;
801808 }
802809
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 )
804812 orphaned_commit_warning (old .commit , new -> commit );
805813
806814 update_refs_for_switch (opts , & old , new );
@@ -810,6 +818,76 @@ static int switch_branches(const struct checkout_opts *opts,
810818 return ret || writeout_error ;
811819}
812820
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+
813891static int git_checkout_config (const char * var , const char * value , void * cb )
814892{
815893 if (!strcmp (var , "diff.ignoresubmodules" )) {
@@ -1071,6 +1149,9 @@ static int checkout_branch(struct checkout_opts *opts,
10711149 die (_ ("Cannot switch branch to a non-commit '%s'" ),
10721150 new -> name );
10731151
1152+ if (opts -> new_worktree )
1153+ return prepare_linked_checkout (opts , new );
1154+
10741155 if (!new -> commit && opts -> new_branch ) {
10751156 unsigned char rev [20 ];
10761157 int flag ;
@@ -1113,6 +1194,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
11131194 N_ ("do not limit pathspecs to sparse entries only" )),
11141195 OPT_HIDDEN_BOOL (0 , "guess" , & dwim_new_local_branch ,
11151196 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" )),
11161199 OPT_END (),
11171200 };
11181201
@@ -1121,6 +1204,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
11211204 opts .overwrite_ignore = 1 ;
11221205 opts .prefix = prefix ;
11231206
1207+ opts .saved_argv = xmalloc (sizeof (const char * ) * (argc + 2 ));
1208+ memcpy (opts .saved_argv , argv , sizeof (const char * ) * (argc + 1 ));
1209+
11241210 gitmodules_config ();
11251211 git_config (git_checkout_config , & opts );
11261212
@@ -1129,6 +1215,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
11291215 argc = parse_options (argc , argv , prefix , options , checkout_usage ,
11301216 PARSE_OPT_KEEP_DASHDASH );
11311217
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+
11321223 if (conflict_style ) {
11331224 opts .merge = 1 ; /* implied */
11341225 git_xmerge_config ("merge.conflictstyle" , conflict_style , NULL );
0 commit comments