@@ -648,10 +648,10 @@ struct GitInputScheme : InputScheme
648648 }
649649
650650 /* *
651- * Get a `SourceAccessor` for the given Git revision by creating a git archive and unpacking it to the Nix store.
652- * This is used for Nix < 2.20 compatibility .
651+ * Get a `SourceAccessor` for the given Git revision using Nix < 2.20 semantics, i.e. using `git archive` or `git
652+ * checkout` .
653653 */
654- ref<SourceAccessor> getGitArchiveAccessor (
654+ ref<SourceAccessor> getLegacyGitAccessor (
655655 Store & store,
656656 RepoInfo & repoInfo,
657657 const std::filesystem::path & repoDir,
@@ -661,27 +661,49 @@ struct GitInputScheme : InputScheme
661661 auto tmpDir = createTempDir ();
662662 AutoDelete delTmpDir (tmpDir, true );
663663
664- auto source = sinkToSource ([&](Sink & sink) {
665- runProgram2 (
666- {.program = " git" ,
667- .args = {" -C" , repoDir, " --git-dir" , repoInfo.gitDir , " archive" , rev.gitRev ()},
668- .standardOut = &sink});
669- });
670-
671- unpackTarfile (*source, tmpDir);
672-
673- auto storePath = store.addToStore (" source" , {getFSSourceAccessor (), CanonPath (tmpDir)});
664+ auto storePath =
665+ options.submodules
666+ ? [&]() {
667+ // Nix < 2.20 used `git checkout` for repos with submodules.
668+ runProgram2 ({.program = " git" , .args = {" init" , tmpDir}});
669+ runProgram2 ({.program = " git" , .args = {" -C" , tmpDir, " remote" , " add" , " origin" , repoDir}});
670+ runProgram2 ({.program = " git" , .args = {" -C" , tmpDir, " fetch" , " origin" , rev.gitRev ()}});
671+ runProgram2 ({.program = " git" , .args = {" -C" , tmpDir, " checkout" , rev.gitRev ()}});
672+ PathFilter filter = [&](const Path & path) { return baseNameOf (path) != " .git" ; };
673+ return store.addToStore (
674+ " source" ,
675+ {getFSSourceAccessor (), CanonPath (tmpDir)},
676+ ContentAddressMethod::Raw::NixArchive,
677+ HashAlgorithm::SHA256,
678+ {},
679+ filter);
680+ }()
681+ : [&]() {
682+ // Nix < 2.20 used `git archive` for repos without submodules.
683+ options.exportIgnore = true ;
684+
685+ auto source = sinkToSource ([&](Sink & sink) {
686+ runProgram2 (
687+ {.program = " git" ,
688+ .args = {" -C" , repoDir, " --git-dir" , repoInfo.gitDir , " archive" , rev.gitRev ()},
689+ .standardOut = &sink});
690+ });
691+
692+ unpackTarfile (*source, tmpDir);
693+
694+ return store.addToStore (" source" , {getFSSourceAccessor (), CanonPath (tmpDir)});
695+ }();
674696
675697 auto accessor = store.getFSAccessor (storePath);
676698
677- options.exportIgnore = true ;
678- accessor->fingerprint = options.makeFingerprint (rev) + " ;f" ;
699+ accessor->fingerprint = options.makeFingerprint (rev) + " ;legacy" ;
679700
680701 return ref{accessor};
681702 }
682703
683704 std::pair<ref<SourceAccessor>, Input>
684705 getAccessorFromCommit (const Settings & settings, ref<Store> store, RepoInfo & repoInfo, Input && input) const
706+
685707 {
686708 assert (!repoInfo.workdirInfo .isDirty );
687709
@@ -833,7 +855,7 @@ struct GitInputScheme : InputScheme
833855 * as well. */
834856 warn (" Using Nix 2.19 semantics to export Git repository '%s'." , input.to_string ());
835857 auto accessorModern = accessor;
836- accessor = getGitArchiveAccessor (*store, repoInfo, repoDir, rev, options);
858+ accessor = getLegacyGitAccessor (*store, repoInfo, repoDir, rev, options);
837859 if (expectedNarHash) {
838860 auto narHashLegacy =
839861 fetchToStore2 (settings, *store, {accessor}, FetchMode::DryRun, input.getName ()).second ;
@@ -851,7 +873,7 @@ struct GitInputScheme : InputScheme
851873 auto narHashNew = fetchToStore2 (settings, *store, {accessor}, FetchMode::DryRun, input.getName ()).second ;
852874 if (expectedNarHash && accessor->pathExists (CanonPath (" .gitattributes" ))) {
853875 if (expectedNarHash != narHashNew) {
854- auto accessorLegacy = getGitArchiveAccessor (*store, repoInfo, repoDir, rev, options);
876+ auto accessorLegacy = getLegacyGitAccessor (*store, repoInfo, repoDir, rev, options);
855877 auto narHashLegacy =
856878 fetchToStore2 (settings, *store, {accessorLegacy}, FetchMode::DryRun, input.getName ()).second ;
857879 if (expectedNarHash == narHashLegacy) {
@@ -1033,7 +1055,7 @@ struct GitInputScheme : InputScheme
10331055
10341056 if (auto rev = input.getRev ())
10351057 // FIXME: this can return a wrong fingerprint for the legacy (`git archive`) case, since we don't know here
1036- // whether to append the `;f ` suffix or not.
1058+ // whether to append the `;legacy ` suffix or not.
10371059 return options.makeFingerprint (*rev);
10381060 else {
10391061 auto repoInfo = getRepoInfo (input);
0 commit comments