@@ -359,21 +359,39 @@ static int find_repo(
359359 git_buf path = GIT_BUF_INIT ;
360360 struct stat st ;
361361 dev_t initial_device = 0 ;
362- bool try_with_dot_git = ((flags & GIT_REPOSITORY_OPEN_BARE ) != 0 );
362+ int min_iterations ;
363+ bool in_dot_git ;
363364 int ceiling_offset ;
364365
365366 git_buf_free (repo_path );
366367
367368 if ((error = git_path_prettify (& path , start_path , NULL )) < 0 )
368369 return error ;
369370
370- ceiling_offset = find_ceiling_dir_offset (path .ptr , ceiling_dirs );
371+ /* in_dot_git toggles each loop:
372+ * /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a
373+ * With GIT_REPOSITORY_OPEN_BARE or GIT_REPOSITORY_OPEN_NO_DOTGIT, we
374+ * assume we started with /a/b/c.git and don't append .git the first
375+ * time through.
376+ * min_iterations indicates the number of iterations left before going
377+ * further counts as a search. */
378+ if (flags & (GIT_REPOSITORY_OPEN_BARE | GIT_REPOSITORY_OPEN_NO_DOTGIT )) {
379+ in_dot_git = true;
380+ min_iterations = 1 ;
381+ } else {
382+ in_dot_git = false;
383+ min_iterations = 2 ;
384+ }
371385
372- if (!try_with_dot_git &&
373- (error = git_buf_joinpath (& path , path .ptr , DOT_GIT )) < 0 )
374- return error ;
386+ while (!error && (min_iterations || !(path .ptr [ceiling_offset ] == 0 ||
387+ (flags & GIT_REPOSITORY_OPEN_NO_SEARCH )))) {
388+ if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT )) {
389+ if (!in_dot_git )
390+ if ((error = git_buf_joinpath (& path , path .ptr , DOT_GIT )) < 0 )
391+ break ;
392+ in_dot_git = !in_dot_git ;
393+ }
375394
376- while (!error && !git_buf_len (repo_path )) {
377395 if (p_stat (path .ptr , & st ) == 0 ) {
378396 /* check that we have not crossed device boundaries */
379397 if (initial_device == 0 )
@@ -414,17 +432,10 @@ static int find_repo(
414432 break ;
415433 }
416434
417- if (try_with_dot_git ) {
418- /* if we tried original dir with and without .git AND either hit
419- * directory ceiling or NO_SEARCH was requested, then be done.
420- */
421- if (path .ptr [ceiling_offset ] == '\0' ||
422- (flags & GIT_REPOSITORY_OPEN_NO_SEARCH ) != 0 )
423- break ;
424- /* otherwise look first for .git item */
425- error = git_buf_joinpath (& path , path .ptr , DOT_GIT );
426- }
427- try_with_dot_git = !try_with_dot_git ;
435+ /* Once we've checked the directory (and .git if applicable),
436+ * find the ceiling for a search. */
437+ if (min_iterations && (-- min_iterations == 0 ))
438+ ceiling_offset = find_ceiling_dir_offset (path .ptr , ceiling_dirs );
428439 }
429440
430441 if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE )) {
@@ -480,6 +491,172 @@ int git_repository_open_bare(
480491 return 0 ;
481492}
482493
494+ static int _git_repository_open_ext_from_env (
495+ git_repository * * out ,
496+ const char * start_path )
497+ {
498+ git_repository * repo = NULL ;
499+ git_index * index = NULL ;
500+ git_odb * odb = NULL ;
501+ git_buf dir_buf = GIT_BUF_INIT ;
502+ git_buf ceiling_dirs_buf = GIT_BUF_INIT ;
503+ git_buf across_fs_buf = GIT_BUF_INIT ;
504+ git_buf index_file_buf = GIT_BUF_INIT ;
505+ git_buf namespace_buf = GIT_BUF_INIT ;
506+ git_buf object_dir_buf = GIT_BUF_INIT ;
507+ git_buf alts_buf = GIT_BUF_INIT ;
508+ git_buf work_tree_buf = GIT_BUF_INIT ;
509+ git_buf common_dir_buf = GIT_BUF_INIT ;
510+ const char * ceiling_dirs = NULL ;
511+ unsigned flags = 0 ;
512+ int error ;
513+
514+ if (!start_path ) {
515+ error = git__getenv (& dir_buf , "GIT_DIR" );
516+ if (error == GIT_ENOTFOUND ) {
517+ giterr_clear ();
518+ start_path = "." ;
519+ } else if (error < 0 )
520+ goto error ;
521+ else {
522+ start_path = git_buf_cstr (& dir_buf );
523+ flags |= GIT_REPOSITORY_OPEN_NO_SEARCH ;
524+ flags |= GIT_REPOSITORY_OPEN_NO_DOTGIT ;
525+ }
526+ }
527+
528+ error = git__getenv (& ceiling_dirs_buf , "GIT_CEILING_DIRECTORIES" );
529+ if (error == GIT_ENOTFOUND )
530+ giterr_clear ();
531+ else if (error < 0 )
532+ goto error ;
533+ else
534+ ceiling_dirs = git_buf_cstr (& ceiling_dirs_buf );
535+
536+ error = git__getenv (& across_fs_buf , "GIT_DISCOVERY_ACROSS_FILESYSTEM" );
537+ if (error == GIT_ENOTFOUND )
538+ giterr_clear ();
539+ else if (error < 0 )
540+ goto error ;
541+ else {
542+ int across_fs = 0 ;
543+ error = git_config_parse_bool (& across_fs , git_buf_cstr (& across_fs_buf ));
544+ if (error < 0 )
545+ goto error ;
546+ if (across_fs )
547+ flags |= GIT_REPOSITORY_OPEN_CROSS_FS ;
548+ }
549+
550+ error = git__getenv (& index_file_buf , "GIT_INDEX_FILE" );
551+ if (error == GIT_ENOTFOUND )
552+ giterr_clear ();
553+ else if (error < 0 )
554+ goto error ;
555+ else {
556+ error = git_index_open (& index , git_buf_cstr (& index_file_buf ));
557+ if (error < 0 )
558+ goto error ;
559+ }
560+
561+ error = git__getenv (& namespace_buf , "GIT_NAMESPACE" );
562+ if (error == GIT_ENOTFOUND )
563+ giterr_clear ();
564+ else if (error < 0 )
565+ goto error ;
566+
567+ error = git__getenv (& object_dir_buf , "GIT_OBJECT_DIRECTORY" );
568+ if (error == GIT_ENOTFOUND )
569+ giterr_clear ();
570+ else if (error < 0 )
571+ goto error ;
572+ else {
573+ error = git_odb_open (& odb , git_buf_cstr (& object_dir_buf ));
574+ if (error < 0 )
575+ goto error ;
576+ }
577+
578+ error = git__getenv (& work_tree_buf , "GIT_WORK_TREE" );
579+ if (error == GIT_ENOTFOUND )
580+ giterr_clear ();
581+ else if (error < 0 )
582+ goto error ;
583+ else {
584+ giterr_set (GITERR_INVALID , "GIT_WORK_TREE unimplemented" );
585+ error = GIT_ERROR ;
586+ goto error ;
587+ }
588+
589+ error = git__getenv (& work_tree_buf , "GIT_COMMON_DIR" );
590+ if (error == GIT_ENOTFOUND )
591+ giterr_clear ();
592+ else if (error < 0 )
593+ goto error ;
594+ else {
595+ giterr_set (GITERR_INVALID , "GIT_COMMON_DIR unimplemented" );
596+ error = GIT_ERROR ;
597+ goto error ;
598+ }
599+
600+ error = git_repository_open_ext (& repo , start_path , flags , ceiling_dirs );
601+ if (error < 0 )
602+ goto error ;
603+
604+ if (odb )
605+ git_repository_set_odb (repo , odb );
606+
607+ error = git__getenv (& alts_buf , "GIT_ALTERNATE_OBJECT_DIRECTORIES" );
608+ if (error == GIT_ENOTFOUND )
609+ giterr_clear ();
610+ else if (error < 0 )
611+ goto error ;
612+ else {
613+ const char * end ;
614+ char * alt , * sep ;
615+ if (!odb ) {
616+ error = git_repository_odb (& odb , repo );
617+ if (error < 0 )
618+ goto error ;
619+ }
620+
621+ end = git_buf_cstr (& alts_buf ) + git_buf_len (& alts_buf );
622+ for (sep = alt = alts_buf .ptr ; sep != end ; alt = sep + 1 ) {
623+ for (sep = alt ; * sep && * sep != GIT_PATH_LIST_SEPARATOR ; sep ++ )
624+ ;
625+ if (* sep )
626+ * sep = '\0' ;
627+ error = git_odb_add_disk_alternate (odb , alt );
628+ if (error < 0 )
629+ goto error ;
630+ }
631+ }
632+
633+ error = git_repository_set_namespace (repo , git_buf_cstr (& namespace_buf ));
634+ if (error < 0 )
635+ goto error ;
636+
637+ git_repository_set_index (repo , index );
638+
639+ if (out ) {
640+ * out = repo ;
641+ goto success ;
642+ }
643+ error :
644+ git_repository_free (repo );
645+ success :
646+ git_odb_free (odb );
647+ git_index_free (index );
648+ git_buf_free (& common_dir_buf );
649+ git_buf_free (& work_tree_buf );
650+ git_buf_free (& alts_buf );
651+ git_buf_free (& object_dir_buf );
652+ git_buf_free (& namespace_buf );
653+ git_buf_free (& index_file_buf );
654+ git_buf_free (& across_fs_buf );
655+ git_buf_free (& ceiling_dirs_buf );
656+ git_buf_free (& dir_buf );
657+ return error ;
658+ }
659+
483660int git_repository_open_ext (
484661 git_repository * * repo_ptr ,
485662 const char * start_path ,
@@ -492,6 +669,9 @@ int git_repository_open_ext(
492669 git_repository * repo ;
493670 git_config * config = NULL ;
494671
672+ if (flags & GIT_REPOSITORY_OPEN_FROM_ENV )
673+ return _git_repository_open_ext_from_env (repo_ptr , start_path );
674+
495675 if (repo_ptr )
496676 * repo_ptr = NULL ;
497677
0 commit comments