Skip to content

Commit

Permalink
fix: better support dangling revisions
Browse files Browse the repository at this point in the history
The submodules branch generates a checkout which depends on only the
references, not all revisions. If there are dangling revisions in the
bare fetcher clone (a correctness issue itself) then the subsequent
temporary directory clone will disastrously fail with messages like
```
fatal: reference is not a tree: 2da0785fa32ce4c628d501c8743c88be00835b50
```
You should be able to reproduce this behavior with
```bash

this_nixpkgs='github:nixos/nixpkgs?rev=36ac8d7e411eeb11ac0998d5a39e329c1226e541';
this_git=$(nix build --print-out-paths "$this_nixpkgs#git")/bin/git;

export GIT_AUTHOR_NAME=foo \
	[email protected] \
	GIT_AUTHOR_DATE=100000000 \
	GIT_COMMITER_NAME=foo \
	[email protected] \
	GIT_COMMITTER_DATE=100000000;

tmpgit=$(mktemp -d);
echo "Repo'll be at $tmpgit";

"$this_git" init "$tmpgit";

"$this_git" -C "$tmpgit" commit --allow-empty -m "foo"; # 8c2146823865b76da067b3bb458611a0a19ede3b
"$this_git" -C "$tmpgit" commit --allow-empty -m "foo"; # 2da0785fa32ce4c628d501c8743c88be00835b50
"$this_git" -C "$tmpgit" reset --hard HEAD~1; # 8c2146823865b76da067b3bb458611a0a19ede3b

for version in 18 19 20 21 22 23 24; do
    echo "Checking nix version 2.$version";
    this_nix=$(nix build "$this_nixpkgs#nixVersions.nix_2_$version^out" --print-out-paths)/bin/nix;

    url="file:///$tmpgit";

    # populate fetcher-v1.sqlite and the gitv3/ dir
    "$this_nix-build" --expr $'builtins.fetchGit {
        url = \"'"$url"$'\";
        rev = \"8c2146823865b76da067b3bb458611a0a19ede3b\";
        submodules = true;
    }';

    # put the "corrupted" git dir in place of the fetched one
    cache_dir="${XDG_CONFIG_HOME:-$HOME}"/.cache/nix/gitv3;
    tmp=$(mktemp);
    printf "%s" "$url" >"$tmp";
    fetched_dir="$cache_dir"/$(printf "%s" "$url" | $this_nix --extra-experimental-features nix-command hash file --type sha256 --base32 "$tmp");
    rm -rf "$fetched_dir";
    git clone --bare "$tmpgit" "$fetched_dir";

    # See if we can realise the derivation pointing to the dangling commit
    _NIX_FORCE_HTTP=1 "$this_nix-build" --impure --expr $'
    { pkgs ? (import <nixpkgs> { }) }: pkgs.stdenv.mkDerivation {
      pname = "foo";
      version = "1.0.0";
      dontUnpack = true;

      '"
      src = builtins.fetchGit {
        url = \"file:///$tmpgit\";
        rev = \"2da0785fa32ce4c628d501c8743c88be00835b50\";
        submodules = true;
      };

      buildPhase = ''
        touch \$out;
        exit 0;
      '';
    }
    "
done
```
This change set also reports such an inconsistency (printTalkative) with
an associated attempt to redress the inconsistency with a fresh fetch.
It also avoids this issue in the submodules path by simply checking out
the specified revision (in addition to all references to preserve the
original behavior - although, I think _only_ the revision is necessary).
  • Loading branch information
johnrichardrinehart committed Oct 26, 2024
1 parent 5f20e42 commit 31046c4
Showing 1 changed file with 6 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/libfetchers/git.cc
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,11 @@ struct GitInputScheme : InputScheme
if (input.getRev()) {
try {
runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "cat-file", "-e", input.getRev()->gitRev() });
auto res = runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "for-each-ref", fmt("--contains=%s", input.getRev()->gitRev()) });
if ( res == "" ){
printTalkative("Rev %s was not associated with any ref (possibly due to an incomplete fetch) - performing a fetch", input.getRev()->gitRev(), actualUrl);
doFetch = true;
}
doFetch = false;
} catch (ExecError & e) {
if (WIFEXITED(e.status)) {
Expand Down Expand Up @@ -630,7 +635,7 @@ struct GitInputScheme : InputScheme
// everything to ensure we get the rev.
Activity act(*logger, lvlTalkative, actUnknown, fmt("making temporary clone of '%s'", repoDir));
runProgram("git", true, { "-C", tmpDir, "fetch", "--quiet", "--force",
"--update-head-ok", "--", repoDir, "refs/*:refs/*" }, {}, true);
"--update-head-ok", "--", repoDir, "refs/*:refs/*", input.getRev()->gitRev() }, {}, true);
}

runProgram("git", true, { "-C", tmpDir, "checkout", "--quiet", input.getRev()->gitRev() });
Expand Down

0 comments on commit 31046c4

Please sign in to comment.