Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix repository discovery with ceiling_dirs at current directory #3727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

joshtriplett
Copy link
Contributor

git only checks ceiling directories when its search ascends to a parent
directory. A ceiling directory matching the starting directory will not
prevent git from finding a repository in the starting directory or a
parent directory. libgit2 handled the former case correctly, but
differed from git in the latter case: given a ceiling directory matching
the starting directory, but no repository at the starting directory,
libgit2 would stop the search at that point rather than finding a
repository in a parent directory.

Test case using git command-line tools:

/tmp$ git init x
Initialized empty Git repository in /tmp/x/.git/
/tmp$ cd x/
/tmp/x$ mkdir subdir
/tmp/x$ cd subdir/
/tmp/x/subdir$ GIT_CEILING_DIRECTORIES=/tmp/x git rev-parse --git-dir
fatal: Not a git repository (or any of the parent directories): .git
/tmp/x/subdir$ GIT_CEILING_DIRECTORIES=/tmp/x/subdir git rev-parse --git-dir
/tmp/x/.git

Fix the testsuite to test this case (in one case fixing a test that
depended on the current behavior), and then fix find_repo to handle this
case correctly.

In the process, simplify and document the logic in find_repo():

  • Separate the concepts of "currently checking a .git directory" and
    "number of iterations left before going further counts as a search"
    into two separate variables, in_dot_git and min_iterations.
  • Move the logic to handle in_dot_git and append /.git to the top of the
    loop.
  • Only search ceiling_dirs and find ceiling_offset after running out of
    min_iterations; since ceiling_offset only tracks the longest matching
    ceiling directory, if ceiling_dirs contained both the current
    directory and a parent directory, this change makes find_repo stop the
    search at the parent directory.

@joshtriplett
Copy link
Contributor Author

I ran into this issue while writing and testing test cases for #3711. I wrote some test cases for this corner case in $GIT_CEILING_DIRECTORIES, found that they failed, and then found I could reproduce the issue using git_repository_open_ext or git_repository_discover without using any of the new code.

The new behavior, and the new tests, match the way the git command-line tools handle $GIT_CEILING_DIRECTORIES.

@joshtriplett
Copy link
Contributor Author

Any thoughts on this bug? Do the test cases seem reasonable, as expressions of git's own behavior? Does the rewritten logic seem like an improvement in clarity?

ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);

//this must pass as ceiling_directories cannot prevent the current
//working directory to be checked
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We avoid C++-style comments (it seems this file has at least one instance of this already, but let's not let it get out of control)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, I can change all of the new comments to /* C style */.

git only checks ceiling directories when its search ascends to a parent
directory.  A ceiling directory matching the starting directory will not
prevent git from finding a repository in the starting directory or a
parent directory.  libgit2 handled the former case correctly, but
differed from git in the latter case: given a ceiling directory matching
the starting directory, but no repository at the starting directory,
libgit2 would stop the search at that point rather than finding a
repository in a parent directory.

Test case using git command-line tools:

/tmp$ git init x
Initialized empty Git repository in /tmp/x/.git/
/tmp$ cd x/
/tmp/x$ mkdir subdir
/tmp/x$ cd subdir/
/tmp/x/subdir$ GIT_CEILING_DIRECTORIES=/tmp/x git rev-parse --git-dir
fatal: Not a git repository (or any of the parent directories): .git
/tmp/x/subdir$ GIT_CEILING_DIRECTORIES=/tmp/x/subdir git rev-parse --git-dir
/tmp/x/.git

Fix the testsuite to test this case (in one case fixing a test that
depended on the current behavior), and then fix find_repo to handle this
case correctly.

In the process, simplify and document the logic in find_repo():
- Separate the concepts of "currently checking a .git directory" and
  "number of iterations left before going further counts as a search"
  into two separate variables, in_dot_git and min_iterations.
- Move the logic to handle in_dot_git and append /.git to the top of the
  loop.
- Only search ceiling_dirs and find ceiling_offset after running out of
  min_iterations; since ceiling_offset only tracks the longest matching
  ceiling directory, if ceiling_dirs contained both the current
  directory and a parent directory, this change makes find_repo stop the
  search at the parent directory.
@joshtriplett joshtriplett force-pushed the discover-ceiling-fix branch from 47d263c to fb714f6 Compare April 22, 2016 13:50
@joshtriplett
Copy link
Contributor Author

Updated to use exclusively /* C-style comments */.

@joshtriplett
Copy link
Contributor Author

Following up on this; any issues with the new version of the pull request?

@ethomson
Copy link
Member

Sorry about the delay in getting back to you. I think that this is overall a good change, but I'm finding the find_repo function a bit hard to process. This was true before your change, but since we're refactoring it, I wonder if we can clean it up a bit to reduce some of the cognitive load it puts on us.

For example, we if (!error) do something a lot. It seems like we should either just jump to the end of the function if we need to clean something up. (And if we don't, let's just return in place.)

Things like if (!(error = read_gitfile(&repo_link, path.ptr))) { do a bunch of work } seem like they could better be expressed as if if ((error = read_gitfile(&repo_link, path.ptr))) { exit } and reduce the indentation level there.

It seems like the logic here is correct, but cleaning this up a bit might make it easier to review, if that's something you're willing to do. Thanks!

@joshtriplett
Copy link
Contributor Author

I think that this is overall a good change, but I'm finding the find_repo function a bit hard to process. This was true before your change, but since we're refactoring it, I wonder if we can clean it up a bit to reduce some of the cognitive load it puts on us.

👍 It took me quite a while to work through its logic myself, so that sounds good to me.

It seems like the logic here is correct, but cleaning this up a bit might make it easier to review, if that's something you're willing to do. Thanks!

Sure, I'd be happy to do so. To some extent, I'd tried to reduce the amount of refactoring to the minimal amount needed to make the logic clearer, because I didn't want to make this more difficult to review.

If you don't mind, I'd like to make this a two-patch series, with the first patch fixing this logic bug and doing some minimal refactoring, and the second doing some more aggressive refactoring. Does that sound reasonable?

@ethomson
Copy link
Member

Awesome, thank you.

If you don't mind, I'd like to make this a two-patch series, with the first patch fixing this logic bug and doing some minimal refactoring, and the second doing some more aggressive refactoring. Does that sound reasonable?

Fine with me! Thanks for tackling the refactoring. 😀

@ethomson
Copy link
Member

ethomson commented Jul 1, 2016

Included with #3711

@ethomson ethomson closed this Jul 1, 2016
@joshtriplett joshtriplett deleted the discover-ceiling-fix branch July 1, 2016 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants