@@ -430,6 +430,11 @@ struct branch_info {
430
430
const char * name ; /* The short name used */
431
431
const char * path ; /* The full name of a real branch */
432
432
struct commit * commit ; /* The named commit */
433
+ /*
434
+ * if not null the branch is detached because it's already
435
+ * checked out in this checkout
436
+ */
437
+ char * checkout ;
433
438
};
434
439
435
440
static void setup_branch_path (struct branch_info * branch )
@@ -958,12 +963,78 @@ static const char *unique_tracking_name(const char *name, unsigned char *sha1)
958
963
return NULL ;
959
964
}
960
965
966
+ static void check_linked_checkout (struct branch_info * new , const char * id )
967
+ {
968
+ struct strbuf sb = STRBUF_INIT ;
969
+ struct strbuf path = STRBUF_INIT ;
970
+ struct strbuf gitdir = STRBUF_INIT ;
971
+ const char * start , * end ;
972
+
973
+ if (id )
974
+ strbuf_addf (& path , "%s/worktrees/%s/HEAD" , get_git_common_dir (), id );
975
+ else
976
+ strbuf_addf (& path , "%s/HEAD" , get_git_common_dir ());
977
+
978
+ if (strbuf_read_file (& sb , path .buf , 0 ) < 0 ||
979
+ !skip_prefix (sb .buf , "ref:" , & start ))
980
+ goto done ;
981
+ while (isspace (* start ))
982
+ start ++ ;
983
+ end = start ;
984
+ while (* end && !isspace (* end ))
985
+ end ++ ;
986
+ if (strncmp (start , new -> path , end - start ) || new -> path [end - start ] != '\0' )
987
+ goto done ;
988
+ if (id ) {
989
+ strbuf_reset (& path );
990
+ strbuf_addf (& path , "%s/worktrees/%s/gitdir" , get_git_common_dir (), id );
991
+ if (strbuf_read_file (& gitdir , path .buf , 0 ) <= 0 )
992
+ goto done ;
993
+ strbuf_rtrim (& gitdir );
994
+ } else
995
+ strbuf_addstr (& gitdir , get_git_common_dir ());
996
+ die (_ ("'%s' is already checked out at '%s'" ), new -> name , gitdir .buf );
997
+ done :
998
+ strbuf_release (& path );
999
+ strbuf_release (& sb );
1000
+ strbuf_release (& gitdir );
1001
+ }
1002
+
1003
+ static void check_linked_checkouts (struct branch_info * new )
1004
+ {
1005
+ struct strbuf path = STRBUF_INIT ;
1006
+ DIR * dir ;
1007
+ struct dirent * d ;
1008
+
1009
+ strbuf_addf (& path , "%s/worktrees" , get_git_common_dir ());
1010
+ if ((dir = opendir (path .buf )) == NULL ) {
1011
+ strbuf_release (& path );
1012
+ return ;
1013
+ }
1014
+
1015
+ /*
1016
+ * $GIT_COMMON_DIR/HEAD is practically outside
1017
+ * $GIT_DIR so resolve_ref_unsafe() won't work (it
1018
+ * uses git_path). Parse the ref ourselves.
1019
+ */
1020
+ check_linked_checkout (new , NULL );
1021
+
1022
+ while ((d = readdir (dir )) != NULL ) {
1023
+ if (!strcmp (d -> d_name , "." ) || !strcmp (d -> d_name , ".." ))
1024
+ continue ;
1025
+ check_linked_checkout (new , d -> d_name );
1026
+ }
1027
+ strbuf_release (& path );
1028
+ closedir (dir );
1029
+ }
1030
+
961
1031
static int parse_branchname_arg (int argc , const char * * argv ,
962
1032
int dwim_new_local_branch_ok ,
963
1033
struct branch_info * new ,
964
1034
struct tree * * source_tree ,
965
1035
unsigned char rev [20 ],
966
- const char * * new_branch )
1036
+ const char * * new_branch ,
1037
+ int force_detach )
967
1038
{
968
1039
int argcount = 0 ;
969
1040
unsigned char branch_rev [20 ];
@@ -1085,6 +1156,16 @@ static int parse_branchname_arg(int argc, const char **argv,
1085
1156
else
1086
1157
new -> path = NULL ; /* not an existing branch */
1087
1158
1159
+ if (new -> path && !force_detach && !* new_branch ) {
1160
+ unsigned char sha1 [20 ];
1161
+ int flag ;
1162
+ char * head_ref = resolve_refdup ("HEAD" , 0 , sha1 , & flag );
1163
+ if (head_ref &&
1164
+ (!(flag & REF_ISSYMREF ) || strcmp (head_ref , new -> path )))
1165
+ check_linked_checkouts (new );
1166
+ free (head_ref );
1167
+ }
1168
+
1088
1169
new -> commit = lookup_commit_reference_gently (rev , 1 );
1089
1170
if (!new -> commit ) {
1090
1171
/* not a commit */
@@ -1289,7 +1370,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1289
1370
!opts .new_branch ;
1290
1371
int n = parse_branchname_arg (argc , argv , dwim_ok ,
1291
1372
& new , & opts .source_tree ,
1292
- rev , & opts .new_branch );
1373
+ rev , & opts .new_branch ,
1374
+ opts .force_detach );
1293
1375
argv += n ;
1294
1376
argc -= n ;
1295
1377
}
0 commit comments