@@ -38,6 +38,8 @@ GIT__USE_STRMAP
3838
3939static int check_repositoryformatversion (git_config * config );
4040
41+ #define GIT_COMMONDIR_FILE "commondir"
42+
4143#define GIT_FILE_CONTENT_PREFIX "gitdir:"
4244
4345#define GIT_BRANCH_MASTER "master"
@@ -143,6 +145,7 @@ void git_repository_free(git_repository *repo)
143145
144146 git__free (repo -> path_gitlink );
145147 git__free (repo -> path_repository );
148+ git__free (repo -> commondir );
146149 git__free (repo -> workdir );
147150 git__free (repo -> namespace );
148151 git__free (repo -> ident_name );
@@ -157,17 +160,41 @@ void git_repository_free(git_repository *repo)
157160 *
158161 * Open a repository object from its path
159162 */
160- static bool valid_repository_path (git_buf * repository_path )
163+ static bool valid_repository_path (git_buf * repository_path , git_buf * common_path )
161164{
162- /* Check OBJECTS_DIR first, since it will generate the longest path name */
163- if (git_path_contains_dir (repository_path , GIT_OBJECTS_DIR ) == false)
164- return false;
165+ /* Check if we have a separate commondir (e.g. we have a
166+ * worktree) */
167+ if (git_path_contains_file (repository_path , GIT_COMMONDIR_FILE )) {
168+ git_buf common_link = GIT_BUF_INIT ;
169+ git_buf_joinpath (& common_link , repository_path -> ptr , GIT_COMMONDIR_FILE );
170+
171+ git_futils_readbuffer (& common_link , common_link .ptr );
172+ git_buf_rtrim (& common_link );
173+
174+ if (git_path_is_relative (common_link .ptr )) {
175+ git_buf_joinpath (common_path , repository_path -> ptr , common_link .ptr );
176+ } else {
177+ git_buf_swap (common_path , & common_link );
178+ }
179+
180+ git_buf_free (& common_link );
181+ }
182+ else {
183+ git_buf_set (common_path , repository_path -> ptr , repository_path -> size );
184+ }
185+
186+ /* Make sure the commondir path always has a trailing * slash */
187+ if (git_buf_rfind (common_path , '/' ) != (ssize_t )common_path -> size - 1 )
188+ git_buf_putc (common_path , '/' );
165189
166190 /* Ensure HEAD file exists */
167191 if (git_path_contains_file (repository_path , GIT_HEAD_FILE ) == false)
168192 return false;
169193
170- if (git_path_contains_dir (repository_path , GIT_REFS_DIR ) == false)
194+ /* Check files in common dir */
195+ if (git_path_contains_dir (common_path , GIT_OBJECTS_DIR ) == false)
196+ return false;
197+ if (git_path_contains_dir (common_path , GIT_REFS_DIR ) == false)
171198 return false;
172199
173200 return true;
@@ -356,13 +383,15 @@ static int find_repo(
356383 git_buf * repo_path ,
357384 git_buf * parent_path ,
358385 git_buf * link_path ,
386+ git_buf * common_path ,
359387 const char * start_path ,
360388 uint32_t flags ,
361389 const char * ceiling_dirs )
362390{
363391 int error ;
364392 git_buf path = GIT_BUF_INIT ;
365393 git_buf repo_link = GIT_BUF_INIT ;
394+ git_buf common_link = GIT_BUF_INIT ;
366395 struct stat st ;
367396 dev_t initial_device = 0 ;
368397 int min_iterations ;
@@ -409,21 +438,27 @@ static int find_repo(
409438 break ;
410439
411440 if (S_ISDIR (st .st_mode )) {
412- if (valid_repository_path (& path )) {
441+ if (valid_repository_path (& path , & common_link )) {
413442 git_path_to_dir (& path );
414443 git_buf_set (repo_path , path .ptr , path .size );
444+
445+ if (common_path )
446+ git_buf_swap (& common_link , common_path );
447+
415448 break ;
416449 }
417450 }
418451 else if (S_ISREG (st .st_mode ) && git__suffixcmp (path .ptr , "/" DOT_GIT ) == 0 ) {
419452 error = read_gitfile (& repo_link , path .ptr );
420453 if (error < 0 )
421454 break ;
422- if (valid_repository_path (& repo_link )) {
455+ if (valid_repository_path (& repo_link , & common_link )) {
423456 git_buf_swap (repo_path , & repo_link );
424457
425458 if (link_path )
426459 error = git_buf_put (link_path , path .ptr , path .size );
460+ if (common_path )
461+ git_buf_swap (& common_link , common_path );
427462 }
428463 break ;
429464 }
@@ -470,6 +505,7 @@ static int find_repo(
470505
471506 git_buf_free (& path );
472507 git_buf_free (& repo_link );
508+ git_buf_free (& common_link );
473509 return error ;
474510}
475511
@@ -478,14 +514,15 @@ int git_repository_open_bare(
478514 const char * bare_path )
479515{
480516 int error ;
481- git_buf path = GIT_BUF_INIT ;
517+ git_buf path = GIT_BUF_INIT , common_path = GIT_BUF_INIT ;
482518 git_repository * repo = NULL ;
483519
484520 if ((error = git_path_prettify_dir (& path , bare_path , NULL )) < 0 )
485521 return error ;
486522
487- if (!valid_repository_path (& path )) {
523+ if (!valid_repository_path (& path , & common_path )) {
488524 git_buf_free (& path );
525+ git_buf_free (& common_path );
489526 giterr_set (GITERR_REPOSITORY , "path is not a repository: %s" , bare_path );
490527 return GIT_ENOTFOUND ;
491528 }
@@ -495,6 +532,8 @@ int git_repository_open_bare(
495532
496533 repo -> path_repository = git_buf_detach (& path );
497534 GITERR_CHECK_ALLOC (repo -> path_repository );
535+ repo -> commondir = git_buf_detach (& common_path );
536+ GITERR_CHECK_ALLOC (repo -> commondir );
498537
499538 /* of course we're bare! */
500539 repo -> is_bare = 1 ;
@@ -681,7 +720,7 @@ int git_repository_open_ext(
681720{
682721 int error ;
683722 git_buf path = GIT_BUF_INIT , parent = GIT_BUF_INIT ,
684- link_path = GIT_BUF_INIT ;
723+ link_path = GIT_BUF_INIT , common_path = GIT_BUF_INIT ;
685724 git_repository * repo ;
686725 git_config * config = NULL ;
687726
@@ -692,7 +731,7 @@ int git_repository_open_ext(
692731 * repo_ptr = NULL ;
693732
694733 error = find_repo (
695- & path , & parent , & link_path , start_path , flags , ceiling_dirs );
734+ & path , & parent , & link_path , & common_path , start_path , flags , ceiling_dirs );
696735
697736 if (error < 0 || !repo_ptr )
698737 return error ;
@@ -707,6 +746,10 @@ int git_repository_open_ext(
707746 repo -> path_gitlink = git_buf_detach (& link_path );
708747 GITERR_CHECK_ALLOC (repo -> path_gitlink );
709748 }
749+ if (common_path .size ) {
750+ repo -> commondir = git_buf_detach (& common_path );
751+ GITERR_CHECK_ALLOC (repo -> commondir );
752+ }
710753
711754 /*
712755 * We'd like to have the config, but git doesn't particularly
@@ -773,7 +816,7 @@ int git_repository_discover(
773816
774817 git_buf_sanitize (out );
775818
776- return find_repo (out , NULL , NULL , start_path , flags , ceiling_dirs );
819+ return find_repo (out , NULL , NULL , NULL , start_path , flags , ceiling_dirs );
777820}
778821
779822static int load_config (
@@ -928,7 +971,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
928971 git_buf odb_path = GIT_BUF_INIT ;
929972 git_odb * odb ;
930973
931- if ((error = git_buf_joinpath (& odb_path , repo -> path_repository , GIT_OBJECTS_DIR )) < 0 )
974+ if ((error = git_buf_joinpath (& odb_path , repo -> commondir , GIT_OBJECTS_DIR )) < 0 )
932975 return error ;
933976
934977 error = git_odb_open (& odb , odb_path .ptr );
@@ -1856,7 +1899,8 @@ int git_repository_init_ext(
18561899 git_repository_init_options * opts )
18571900{
18581901 int error ;
1859- git_buf repo_path = GIT_BUF_INIT , wd_path = GIT_BUF_INIT ;
1902+ git_buf repo_path = GIT_BUF_INIT , wd_path = GIT_BUF_INIT ,
1903+ common_path = GIT_BUF_INIT ;
18601904 const char * wd ;
18611905
18621906 assert (out && given_repo && opts );
@@ -1868,7 +1912,7 @@ int git_repository_init_ext(
18681912 goto cleanup ;
18691913
18701914 wd = (opts -> flags & GIT_REPOSITORY_INIT_BARE ) ? NULL : git_buf_cstr (& wd_path );
1871- if (valid_repository_path (& repo_path )) {
1915+ if (valid_repository_path (& repo_path , & common_path )) {
18721916
18731917 if ((opts -> flags & GIT_REPOSITORY_INIT_NO_REINIT ) != 0 ) {
18741918 giterr_set (GITERR_REPOSITORY ,
@@ -1901,6 +1945,7 @@ int git_repository_init_ext(
19011945 error = repo_init_create_origin (* out , opts -> origin_url );
19021946
19031947cleanup :
1948+ git_buf_free (& common_path );
19041949 git_buf_free (& repo_path );
19051950 git_buf_free (& wd_path );
19061951
@@ -2023,6 +2068,12 @@ const char *git_repository_workdir(git_repository *repo)
20232068 return repo -> workdir ;
20242069}
20252070
2071+ const char * git_repository_commondir (git_repository * repo )
2072+ {
2073+ assert (repo );
2074+ return repo -> commondir ;
2075+ }
2076+
20262077int git_repository_set_workdir (
20272078 git_repository * repo , const char * workdir , int update_gitlink )
20282079{
0 commit comments