Skip to content

Commit 2b49028

Browse files
committed
find_repo: Clean up and simplify logic
find_repo had a complex loop and heavily nested conditionals, making it difficult to follow. Simplify this as much as possible: - Separate assignments from conditionals. - Check the complex loop condition in the only place it can change. - Break out of the loop on error, rather than going through the rest of the loop body first. - Handle error cases by immediately breaking, rather than nesting conditionals. - Free repo_link unconditionally on the way out of the function, rather than in multiple places. - Add more comments on the remaining complex steps.
1 parent 0dd98b6 commit 2b49028

File tree

1 file changed

+30
-22
lines changed

1 file changed

+30
-22
lines changed

src/repository.c

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ static int find_repo(
357357
{
358358
int error;
359359
git_buf path = GIT_BUF_INIT;
360+
git_buf repo_link = GIT_BUF_INIT;
360361
struct stat st;
361362
dev_t initial_device = 0;
362363
int min_iterations;
@@ -365,7 +366,8 @@ static int find_repo(
365366

366367
git_buf_free(repo_path);
367368

368-
if ((error = git_path_prettify(&path, start_path, NULL)) < 0)
369+
error = git_path_prettify(&path, start_path, NULL);
370+
if (error < 0)
369371
return error;
370372

371373
/* in_dot_git toggles each loop:
@@ -383,12 +385,13 @@ static int find_repo(
383385
min_iterations = 2;
384386
}
385387

386-
while (!error && (min_iterations || !(path.ptr[ceiling_offset] == 0 ||
387-
(flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))) {
388+
for (;;) {
388389
if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
389-
if (!in_dot_git)
390-
if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
390+
if (!in_dot_git) {
391+
error = git_buf_joinpath(&path, path.ptr, DOT_GIT);
392+
if (error < 0)
391393
break;
394+
}
392395
in_dot_git = !in_dot_git;
393396
}
394397

@@ -397,7 +400,7 @@ static int find_repo(
397400
if (initial_device == 0)
398401
initial_device = st.st_dev;
399402
else if (st.st_dev != initial_device &&
400-
(flags & GIT_REPOSITORY_OPEN_CROSS_FS) == 0)
403+
!(flags & GIT_REPOSITORY_OPEN_CROSS_FS))
401404
break;
402405

403406
if (S_ISDIR(st.st_mode)) {
@@ -408,25 +411,22 @@ static int find_repo(
408411
}
409412
}
410413
else if (S_ISREG(st.st_mode)) {
411-
git_buf repo_link = GIT_BUF_INIT;
412-
413-
if (!(error = read_gitfile(&repo_link, path.ptr))) {
414-
if (valid_repository_path(&repo_link)) {
415-
git_buf_swap(repo_path, &repo_link);
416-
417-
if (link_path)
418-
error = git_buf_put(link_path,
419-
path.ptr, path.size);
420-
}
421-
422-
git_buf_free(&repo_link);
414+
error = read_gitfile(&repo_link, path.ptr);
415+
if (error < 0)
423416
break;
417+
if (valid_repository_path(&repo_link)) {
418+
git_buf_swap(repo_path, &repo_link);
419+
420+
if (link_path)
421+
error = git_buf_put(link_path, path.ptr, path.size);
424422
}
425-
git_buf_free(&repo_link);
423+
break;
426424
}
427425
}
428426

429-
/* move up one directory level */
427+
/* Move up one directory. If we're in_dot_git, we'll search the
428+
* parent itself next. If we're !in_dot_git, we'll search .git
429+
* in the parent directory next (added at the top of the loop). */
430430
if (git_path_dirname_r(&path, path.ptr) < 0) {
431431
error = -1;
432432
break;
@@ -436,6 +436,12 @@ static int find_repo(
436436
* find the ceiling for a search. */
437437
if (min_iterations && (--min_iterations == 0))
438438
ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
439+
440+
/* Check if we should stop searching here. */
441+
if (min_iterations == 0
442+
&& (path.ptr[ceiling_offset] == 0
443+
|| (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))
444+
break;
439445
}
440446

441447
if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
@@ -449,14 +455,16 @@ static int find_repo(
449455
return -1;
450456
}
451457

452-
git_buf_free(&path);
453-
458+
/* If we didn't find the repository, and we don't have any other error
459+
* to report, report that. */
454460
if (!git_buf_len(repo_path) && !error) {
455461
giterr_set(GITERR_REPOSITORY,
456462
"Could not find repository from '%s'", start_path);
457463
error = GIT_ENOTFOUND;
458464
}
459465

466+
git_buf_free(&path);
467+
git_buf_free(&repo_link);
460468
return error;
461469
}
462470

0 commit comments

Comments
 (0)