git fetcher: improve check for valid repository
The .git/refs/heads directory might be empty for a valid usable git repository. This often happens in CI environments, which might only fetch commits, not branches. Therefore instead we let git itself check if HEAD points to something that looks like a commit. fixes #5302
This commit is contained in:
parent
9bc03adbba
commit
0bfa0cdea1
|
@ -220,21 +220,21 @@ struct GitInputScheme : InputScheme
|
||||||
if (!input.getRef() && !input.getRev() && isLocal) {
|
if (!input.getRef() && !input.getRev() && isLocal) {
|
||||||
bool clean = false;
|
bool clean = false;
|
||||||
|
|
||||||
/* Check whether this repo has any commits. There are
|
/* Check whether HEAD points to something that looks like a commit,
|
||||||
probably better ways to do this. */
|
since that is the refrence we want to use later on. */
|
||||||
auto gitDir = actualUrl + "/.git";
|
bool hasHead = false;
|
||||||
auto commonGitDir = chomp(runProgram(
|
try {
|
||||||
"git",
|
runProgram("git", true, { "-C", actualUrl, "rev-parse", "--verify", "--no-revs", "HEAD^{commit}" });
|
||||||
true,
|
hasHead = true;
|
||||||
{ "-C", actualUrl, "rev-parse", "--git-common-dir" }
|
} catch (ExecError & e) {
|
||||||
));
|
// git exits with status 128 here if it does not detect a repository.
|
||||||
if (commonGitDir != ".git")
|
if (!WIFEXITED(e.status) || WEXITSTATUS(e.status) != 128) {
|
||||||
gitDir = commonGitDir;
|
throw Error("Git tree '%s' is broken.\n'git rev-parse --verify HEAD' failed with exit code %d.", actualUrl, WEXITSTATUS(e.status));
|
||||||
|
}
|
||||||
bool haveCommits = !readDirectory(gitDir + "/refs/heads").empty();
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (haveCommits) {
|
if (hasHead) {
|
||||||
runProgram("git", true, { "-C", actualUrl, "diff-index", "--quiet", "HEAD", "--" });
|
runProgram("git", true, { "-C", actualUrl, "diff-index", "--quiet", "HEAD", "--" });
|
||||||
clean = true;
|
clean = true;
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ struct GitInputScheme : InputScheme
|
||||||
// modified dirty file?
|
// modified dirty file?
|
||||||
input.attrs.insert_or_assign(
|
input.attrs.insert_or_assign(
|
||||||
"lastModified",
|
"lastModified",
|
||||||
haveCommits ? std::stoull(runProgram("git", true, { "-C", actualUrl, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD" })) : 0);
|
hasHead ? std::stoull(runProgram("git", true, { "-C", actualUrl, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD" })) : 0);
|
||||||
|
|
||||||
return {std::move(storePath), input};
|
return {std::move(storePath), input};
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,14 @@ NIX=$(command -v nix)
|
||||||
path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath")
|
path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath")
|
||||||
[[ $path3 = $path5 ]]
|
[[ $path3 = $path5 ]]
|
||||||
|
|
||||||
|
# Fetching from a repo with only a specific revision and no branches should
|
||||||
|
# not fall back to copying files and record correct revision information. See: #5302
|
||||||
|
mkdir $TEST_ROOT/minimal
|
||||||
|
git -C $TEST_ROOT/minimal init
|
||||||
|
git -C $TEST_ROOT/minimal fetch $repo $rev2
|
||||||
|
git -C $TEST_ROOT/minimal checkout $rev2
|
||||||
|
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit { url = $TEST_ROOT/minimal; }).rev") = $rev2 ]]
|
||||||
|
|
||||||
# Fetching a shallow repo shouldn't work by default, because we can't
|
# Fetching a shallow repo shouldn't work by default, because we can't
|
||||||
# return a revCount.
|
# return a revCount.
|
||||||
git clone --depth 1 file://$repo $TEST_ROOT/shallow
|
git clone --depth 1 file://$repo $TEST_ROOT/shallow
|
||||||
|
|
Loading…
Reference in a new issue