Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/libfetchers/git-utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,17 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>

for (size_t n = 0; n < git_commit_parentcount(commit->get()); ++n) {
git_commit * parent;
if (git_commit_parent(&parent, commit->get(), n))
throw Error("getting parent of Git commit '%s': %s", *git_commit_id(commit->get()), git_error_last()->message);
if (git_commit_parent(&parent, commit->get(), n)) {
throw Error(
"Failed to retrieve the parent of Git commit '%s': %s. "
"This may be due to an incomplete repository history. "
"To resolve this, either enable the shallow parameter in your flake URL (?shallow=1) "
"or add set the shallow parameter to true in builtins.fetchGit, "
"or fetch the complete history for this branch.",
*git_commit_id(commit->get()),
git_error_last()->message
);
}
todo.push(Commit(parent));
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/libfetchers/git.cc
Original file line number Diff line number Diff line change
Expand Up @@ -798,8 +798,15 @@ struct GitInputScheme : InputScheme
auto rev = repoInfo.workdirInfo.headRev.value_or(nullRev);

input.attrs.insert_or_assign("rev", rev.gitRev());
<<<<<<< HEAD
input.attrs.insert_or_assign("revCount",
rev == nullRev ? 0 : getRevCount(repoInfo, repoPath, rev));
=======
if (!getShallowAttr(input)) {
input.attrs.insert_or_assign("revCount",
rev == nullRev ? 0 : getRevCount(*input.settings, repoInfo, repoPath, rev));
}
>>>>>>> 0479db934 (fetchGit: don't compute revCount on shallow repository)

verifyCommit(input, repo);
} else {
Expand Down
27 changes: 9 additions & 18 deletions tests/functional/fetchGit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repo=$TEST_ROOT/./git

export _NIX_FORCE_HTTP=1

rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix $TEST_ROOT/worktree $TEST_ROOT/shallow $TEST_ROOT/minimal
rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix $TEST_ROOT/worktree $TEST_ROOT/minimal

git init $repo
git -C $repo config user.email "[email protected]"
Expand Down Expand Up @@ -216,18 +216,6 @@ 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
# return a revCount.
git clone --depth 1 file://$repo $TEST_ROOT/shallow
(! nix eval --impure --raw --expr "(builtins.fetchGit { url = $TEST_ROOT/shallow; ref = \"dev\"; }).outPath")

# But you can request a shallow clone, which won't return a revCount.
path6=$(nix eval --impure --raw --expr "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow\"; ref = \"dev\"; shallow = true; }).outPath")
[[ $path3 = $path6 ]]
[[ $(nix eval --impure --expr "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow\"; ref = \"dev\"; shallow = true; }).revCount or 123") == 123 ]]

expectStderr 1 nix eval --expr 'builtins.fetchTree { type = "git"; url = "file:///foo"; }' | grepQuiet "'fetchTree' will not fetch unlocked input"

# Explicit ref = "HEAD" should work, and produce the same outPath as without ref
path7=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"HEAD\"; }).outPath")
path8=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; }).outPath")
Expand Down Expand Up @@ -292,17 +280,20 @@ path11=$(nix eval --impure --raw --expr "(builtins.fetchGit ./.).outPath")
empty="$TEST_ROOT/empty"
git init "$empty"

emptyAttrs='{ lastModified = 0; lastModifiedDate = "19700101000000"; narHash = "sha256-pQpattmS9VmO3ZIQUFn66az8GSmB4IvYhTTCFn6SUmo="; rev = "0000000000000000000000000000000000000000"; revCount = 0; shortRev = "0000000"; submodules = false; }'

[[ $(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]") = $emptyAttrs ]]
emptyAttrs="{ lastModified = 0; lastModifiedDate = \"19700101000000\"; narHash = \"sha256-pQpattmS9VmO3ZIQUFn66az8GSmB4IvYhTTCFn6SUmo=\"; rev = \"0000000000000000000000000000000000000000\"; revCount = 0; shortRev = \"0000000\"; submodules = false; }"
result=$(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]")
[[ "$result" = "$emptyAttrs" ]]

echo foo > "$empty/x"

[[ $(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]") = $emptyAttrs ]]
result=$(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]")
[[ "$result" = "$emptyAttrs" ]]

git -C "$empty" add x

[[ $(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]") = '{ lastModified = 0; lastModifiedDate = "19700101000000"; narHash = "sha256-wzlAGjxKxpaWdqVhlq55q5Gxo4Bf860+kLeEa/v02As="; rev = "0000000000000000000000000000000000000000"; revCount = 0; shortRev = "0000000"; submodules = false; }' ]]
expected_attrs="{ lastModified = 0; lastModifiedDate = \"19700101000000\"; narHash = \"sha256-wzlAGjxKxpaWdqVhlq55q5Gxo4Bf860+kLeEa/v02As=\"; rev = \"0000000000000000000000000000000000000000\"; revCount = 0; shortRev = \"0000000\"; submodules = false; }"
result=$(nix eval --impure --expr "builtins.removeAttrs (builtins.fetchGit $empty) [\"outPath\"]")
[[ "$result" = "$expected_attrs" ]]

# Test a repo with an empty commit.
git -C "$empty" rm -f x
Expand Down
67 changes: 67 additions & 0 deletions tests/functional/fetchGitShallow.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash

# shellcheck source=common.sh
source common.sh

requireGit

# Create a test repo with multiple commits for all our tests
git init "$TEST_ROOT/shallow-parent"
git -C "$TEST_ROOT/shallow-parent" config user.email "[email protected]"
git -C "$TEST_ROOT/shallow-parent" config user.name "Foobar"

# Add several commits to have history
echo "{ outputs = _: {}; }" > "$TEST_ROOT/shallow-parent/flake.nix"
echo "" > "$TEST_ROOT/shallow-parent/file.txt"
git -C "$TEST_ROOT/shallow-parent" add file.txt flake.nix
git -C "$TEST_ROOT/shallow-parent" commit -m "First commit"

echo "second" > "$TEST_ROOT/shallow-parent/file.txt"
git -C "$TEST_ROOT/shallow-parent" commit -m "Second commit" -a

echo "third" > "$TEST_ROOT/shallow-parent/file.txt"
git -C "$TEST_ROOT/shallow-parent" commit -m "Third commit" -a

# Add a branch for testing ref fetching
git -C "$TEST_ROOT/shallow-parent" checkout -b dev
echo "branch content" > "$TEST_ROOT/shallow-parent/branch-file.txt"
git -C "$TEST_ROOT/shallow-parent" add branch-file.txt
git -C "$TEST_ROOT/shallow-parent" commit -m "Branch commit"

# Make a shallow clone (depth=1)
git clone --depth 1 "file://$TEST_ROOT/shallow-parent" "$TEST_ROOT/shallow-clone"

# Test 1: Fetching a shallow repo shouldn't work by default, because we can't
# return a revCount.
(! nix eval --impure --raw --expr "(builtins.fetchGit { url = \"$TEST_ROOT/shallow-clone\"; ref = \"dev\"; }).outPath")

# Test 2: But you can request a shallow clone, which won't return a revCount.
path=$(nix eval --impure --raw --expr "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow-clone\"; ref = \"dev\"; shallow = true; }).outPath")
# Verify file from dev branch exists
[[ -f "$path/branch-file.txt" ]]
# Verify revCount is missing
[[ $(nix eval --impure --expr "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow-clone\"; ref = \"dev\"; shallow = true; }).revCount or 123") == 123 ]]

# Test 3: Check unlocked input error message
expectStderr 1 nix eval --expr 'builtins.fetchTree { type = "git"; url = "file:///foo"; }' | grepQuiet "'fetchTree' will not fetch unlocked input"

# Test 4: Regression test for revCount in worktrees derived from shallow clones
# Add a worktree to the shallow clone
git -C "$TEST_ROOT/shallow-clone" worktree add "$TEST_ROOT/shallow-worktree"

# Prior to the fix, this would error out because of the shallow clone's
# inability to find parent commits. Now it should return an error.
if nix eval --impure --expr "(builtins.fetchGit { url = \"file://$TEST_ROOT/shallow-worktree\"; }).revCount" 2>/dev/null; then
echo "fetchGit unexpectedly succeeded on shallow clone" >&2
exit 1
fi

# Also verify that fetchTree fails similarly
if nix eval --impure --expr "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow-worktree\"; }).revCount" 2>/dev/null; then
echo "fetchTree unexpectedly succeeded on shallow clone" >&2
exit 1
fi

# Verify that we can shallow fetch the worktree
git -C "$TEST_ROOT/shallow-worktree" rev-list --count HEAD >/dev/null
nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$TEST_ROOT/shallow-worktree\"; shallow = true; }).rev"
1 change: 1 addition & 0 deletions tests/functional/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ suites = [
'gc-runtime.sh',
'tarball.sh',
'fetchGit.sh',
'fetchGitShallow.sh',
'fetchurl.sh',
'fetchPath.sh',
'fetchTree-file.sh',
Expand Down
Loading