2121static int init_is_bare_repository = 0 ;
2222static int init_shared_repository = -1 ;
2323static const char * init_db_template_dir ;
24+ static const char * git_link ;
2425
2526static void safe_create_dir (const char * dir , int share )
2627{
@@ -311,11 +312,67 @@ static void create_object_directory(void)
311312 free (path );
312313}
313314
315+ int set_git_dir_init (const char * git_dir , const char * real_git_dir ,
316+ int exist_ok )
317+ {
318+ if (real_git_dir ) {
319+ struct stat st ;
320+
321+ if (!exist_ok && !stat (git_dir , & st ))
322+ die ("%s already exists" , git_dir );
323+
324+ if (!exist_ok && !stat (real_git_dir , & st ))
325+ die ("%s already exists" , real_git_dir );
326+
327+ /*
328+ * make sure symlinks are resolved because we'll be
329+ * moving the target repo later on in separate_git_dir()
330+ */
331+ git_link = xstrdup (real_path (git_dir ));
332+ }
333+ else {
334+ real_git_dir = real_path (git_dir );
335+ git_link = NULL ;
336+ }
337+ set_git_dir (real_path (real_git_dir ));
338+ return 0 ;
339+ }
340+
341+ static void separate_git_dir (const char * git_dir )
342+ {
343+ struct stat st ;
344+ FILE * fp ;
345+
346+ if (!stat (git_link , & st )) {
347+ const char * src ;
348+
349+ if (S_ISREG (st .st_mode ))
350+ src = read_gitfile_gently (git_link );
351+ else if (S_ISDIR (st .st_mode ))
352+ src = git_link ;
353+ else
354+ die ("unable to handle file type %d" , st .st_mode );
355+
356+ if (rename (src , git_dir ))
357+ die_errno ("unable to move %s to %s" , src , git_dir );
358+ }
359+
360+ fp = fopen (git_link , "w" );
361+ if (!fp )
362+ die ("Could not create git link %s" , git_link );
363+ fprintf (fp , "gitdir: %s\n" , git_dir );
364+ fclose (fp );
365+ }
366+
314367int init_db (const char * template_dir , unsigned int flags )
315368{
316369 int reinit ;
370+ const char * git_dir = get_git_dir ();
317371
318- safe_create_dir (get_git_dir (), 0 );
372+ if (git_link )
373+ separate_git_dir (git_dir );
374+
375+ safe_create_dir (git_dir , 0 );
319376
320377 init_is_bare_repository = is_bare_repository ();
321378
@@ -352,7 +409,6 @@ int init_db(const char *template_dir, unsigned int flags)
352409 }
353410
354411 if (!(flags & INIT_DB_QUIET )) {
355- const char * git_dir = get_git_dir ();
356412 int len = strlen (git_dir );
357413 printf ("%s%s Git repository in %s%s\n" ,
358414 reinit ? "Reinitialized existing" : "Initialized empty" ,
@@ -414,6 +470,7 @@ static const char *const init_db_usage[] = {
414470int cmd_init_db (int argc , const char * * argv , const char * prefix )
415471{
416472 const char * git_dir ;
473+ const char * real_git_dir = NULL ;
417474 const char * work_tree ;
418475 const char * template_dir = NULL ;
419476 unsigned int flags = 0 ;
@@ -427,11 +484,16 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
427484 "specify that the git repository is to be shared amongst several users" ,
428485 PARSE_OPT_OPTARG | PARSE_OPT_NONEG , shared_callback , 0 },
429486 OPT_BIT ('q' , "quiet" , & flags , "be quiet" , INIT_DB_QUIET ),
487+ OPT_STRING ('L' , "separate-git-dir" , & real_git_dir , "gitdir" ,
488+ "separate git dir from working tree" ),
430489 OPT_END ()
431490 };
432491
433492 argc = parse_options (argc , argv , prefix , init_db_options , init_db_usage , 0 );
434493
494+ if (real_git_dir && !is_absolute_path (real_git_dir ))
495+ real_git_dir = xstrdup (real_path (real_git_dir ));
496+
435497 if (argc == 1 ) {
436498 int mkdir_tried = 0 ;
437499 retry :
@@ -522,7 +584,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
522584 set_git_work_tree (real_path (work_tree ));
523585 }
524586
525- set_git_dir ( real_path ( git_dir ) );
587+ set_git_dir_init ( git_dir , real_git_dir , 1 );
526588
527589 return init_db (template_dir , flags );
528590}
0 commit comments