Skip to content

Commit a5a2edc

Browse files
committed
Add option to include untracked files in git and mercurial fetchers
It can be confusing (especially for new users) that the git and mercurial fetchers do not include untracked files. This commit adds an option for the fetchers to include untracked files. The option is disabled by default.
1 parent f450c87 commit a5a2edc

File tree

8 files changed

+55
-7
lines changed

8 files changed

+55
-7
lines changed

src/libfetchers/fetch-settings.hh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ struct FetchSettings : public Config
7070
Setting<bool> warnDirty{this, true, "warn-dirty",
7171
"Whether to warn about dirty Git/Mercurial trees."};
7272

73+
Setting<bool> includeUntrackedFiles{this, false, "include-untracked-files",
74+
"Whether to include untracked files in Git/Mercurial trees."};
75+
7376
Setting<std::string> flakeRegistry{this, "https://channels.nixos.org/flake-registry.json", "flake-registry",
7477
R"(
7578
Path or URI of the global flake registry.

src/libfetchers/git-utils.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
257257
return (*((std::function<int(const char * path, unsigned int statusFlags)> *) payload))(path, statusFlags);
258258
}
259259

260-
WorkdirInfo getWorkdirInfo() override
260+
WorkdirInfo getWorkdirInfo(bool includeUntrackedFiles) override
261261
{
262262
WorkdirInfo info;
263263

@@ -284,6 +284,10 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
284284
git_status_options options = GIT_STATUS_OPTIONS_INIT;
285285
options.flags |= GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
286286
options.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
287+
if (includeUntrackedFiles) {
288+
options.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED |
289+
GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
290+
}
287291
if (git_status_foreach_ext(*this, &options, &statusCallbackTrampoline, &statusCallback))
288292
throw Error("getting working directory status: %s", git_error_last()->message);
289293

src/libfetchers/git-utils.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ struct GitRepo
4848
std::vector<Submodule> submodules;
4949
};
5050

51-
virtual WorkdirInfo getWorkdirInfo() = 0;
51+
virtual WorkdirInfo getWorkdirInfo(bool includeUntrackedFiles) = 0;
5252

5353
/* Get the ref that HEAD points to. */
5454
virtual std::optional<std::string> getWorkdirRef() = 0;

src/libfetchers/git.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ struct GitInputScheme : InputScheme
386386
// If this is a local directory and no ref or revision is
387387
// given, then allow the use of an unclean working tree.
388388
if (!input.getRef() && !input.getRev() && repoInfo.isLocal)
389-
repoInfo.workdirInfo = GitRepo::openRepo(CanonPath(repoInfo.url))->getWorkdirInfo();
389+
repoInfo.workdirInfo = GitRepo::openRepo(CanonPath(repoInfo.url))->getWorkdirInfo(fetchSettings.includeUntrackedFiles);
390390

391391
return repoInfo;
392392
}

src/libfetchers/mercurial.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,10 @@ struct MercurialInputScheme : InputScheme
175175

176176
if (!input.getRef() && !input.getRev() && isLocal && pathExists(actualUrl + "/.hg")) {
177177

178-
bool clean = runHg({ "status", "-R", actualUrl, "--modified", "--added", "--removed" }) == "";
178+
Strings hgStatusOptions = { "status", "-R", actualUrl, "--modified", "--added", "--removed" };
179+
if (fetchSettings.includeUntrackedFiles)
180+
hgStatusOptions.push_back("--unknown");
181+
bool clean = runHg(hgStatusOptions) == "";
179182

180183
if (!clean) {
181184

@@ -190,8 +193,11 @@ struct MercurialInputScheme : InputScheme
190193

191194
input.attrs.insert_or_assign("ref", chomp(runHg({ "branch", "-R", actualUrl })));
192195

196+
hgStatusOptions = { "status", "-R", actualUrl, "--clean", "--modified", "--added", "--no-status", "--print0" };
197+
if (fetchSettings.includeUntrackedFiles)
198+
hgStatusOptions.push_back("--unknown");
193199
auto files = tokenizeString<std::set<std::string>>(
194-
runHg({ "status", "-R", actualUrl, "--clean", "--modified", "--added", "--no-status", "--print0" }), "\0"s);
200+
runHg(hgStatusOptions), "\0"s);
195201

196202
Path actualPath(absPath(actualUrl));
197203

tests/functional/fetchGit.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,25 @@ path2=$(nix eval --impure --raw --expr "(builtins.fetchGit $repo).outPath")
106106
[ ! -e $path2/.git ]
107107
[[ $(cat $path2/dir1/foo) = foo ]]
108108

109+
# Using an unclean tree with --include-git-untracked-files option should yield the tracked and uncommitted changes
110+
path21=$(nix eval --include-untracked-files --impure --raw --expr "(builtins.fetchGit $repo).outPath")
111+
[ ! -e $path21/hello ]
112+
[ -e $path21/bar ]
113+
[ -e $path21/dir2/bar ]
114+
[ ! -e $path21/.git ]
115+
[[ $(cat $path21/dir1/foo) = foo ]]
116+
117+
# Using an unclean tree with --include-git-untracked-files option should take into account .gitignore files
118+
echo "/bar" >> $repo/.gitignore
119+
echo "bar" >> $repo/dir2/.gitignore
120+
path22=$(nix eval --include-untracked-files --impure --raw --expr "(builtins.fetchGit $repo).outPath")
121+
[ ! -e $path22/hello ]
122+
[ ! -e $path22/bar ]
123+
[ ! -e $path22/dir2/bar ]
124+
[ ! -e $path22/.git ]
125+
git -C $repo checkout -- $repo/.gitignore
126+
git -C $repo clean -fd
127+
109128
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]]
110129
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).dirtyRev") = "${rev2}-dirty" ]]
111130
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).dirtyShortRev") = "${rev2:0:7}-dirty" ]]

tests/functional/fetchMercurial.sh

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
source common.sh
22

3-
[[ $(type -p hq) ]] || skipTest "Mercurial not installed"
3+
[[ $(type -p hg) ]] || skipTest "Mercurial not installed"
44

55
clearStore
66

@@ -88,6 +88,22 @@ path2=$(nix eval --impure --raw --expr "(builtins.fetchMercurial $repo).outPath"
8888
[ ! -e $path2/.hg ]
8989
[[ $(cat $path2/dir1/foo) = foo ]]
9090

91+
path21=$(nix eval --include-untracked-files --impure --raw --expr "(builtins.fetchMercurial $repo).outPath")
92+
[ ! -e $path21/hello ]
93+
[ -e $path21/bar ]
94+
[ -e $path21/dir2/bar ]
95+
[ ! -e $path21/.hg ]
96+
[[ $(cat $path21/dir1/foo) = foo ]]
97+
98+
echo "bar" >> $repo/.hgignore
99+
path22=$(nix eval --include-untracked-files --impure --raw --expr "(builtins.fetchMercurial $repo).outPath")
100+
[ ! -e $path22/hello ]
101+
[ ! -e $path22/bar ]
102+
[ ! -e $path22/dir2/bar ]
103+
[ ! -e $path22/.git ]
104+
sed -i '/bar/d' $repo/.hgignore
105+
hg status --cwd $repo
106+
91107
[[ $(nix eval --impure --raw --expr "(builtins.fetchMercurial $repo).rev") = 0000000000000000000000000000000000000000 ]]
92108

93109
# ... unless we're using an explicit ref.

tests/functional/flakes/mercurial.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
source ./common.sh
22

3-
[[ $(type -p hq) ]] || skipTest "Mercurial not installed"
3+
[[ $(type -p hg) ]] || skipTest "Mercurial not installed"
44

55
flake1Dir=$TEST_ROOT/flake-hg1
66
mkdir -p $flake1Dir

0 commit comments

Comments
 (0)