diff --git a/doc/manual/command-ref/nix-env.xml b/doc/manual/command-ref/nix-env.xml
index d4563ac47..f0e70a41c 100644
--- a/doc/manual/command-ref/nix-env.xml
+++ b/doc/manual/command-ref/nix-env.xml
@@ -1346,9 +1346,10 @@ $ nix-env --list-generations
This operation deletes the specified generations of the current
profile. The generations can be a list of generation numbers, the
special value old to delete all non-current
-generations, or a value such as 30d to delete all
+generations, a value such as 30d to delete all
generations older than the specified number of days (except for the
-generation that was active at that point in time).
+generation that was active at that point in time), or a value such as.
++5 to delete all but the number of items specified.
Periodically deleting old generations is important to make garbage
collection effective.
@@ -1359,6 +1360,8 @@ collection effective.
$ nix-env --delete-generations 3 4 8
+$ nix-env --delete-generations +5
+
$ nix-env --delete-generations 30d
$ nix-env -p other_profile --delete-generations old
diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc
index 4a607b584..e6300cf05 100644
--- a/src/libstore/profiles.cc
+++ b/src/libstore/profiles.cc
@@ -157,6 +157,29 @@ void deleteGenerations(const Path & profile, const std::set & gens
}
}
+void deleteGenerationsGreaterThan(const Path & profile, const string & max, bool dryRun)
+{
+ int max_keep = 0;
+ PathLocks lock;
+ if(max.size() < 2)
+ throw Error(format("invalid number of generations ‘%1%’") % max);
+ string str_max = string(max, 1, max.size());
+ if (!string2Int(str_max, max_keep) || max_keep == 0)
+ throw Error(format("invalid number of generations to keep ‘%1%’") % max);
+
+ lockProfile(lock, profile);
+
+ int curGen;
+ Generations gens = findGenerations(profile, curGen);
+
+ for (auto i = gens.rbegin(); i != gens.rend(); ++i) {
+ if (max_keep) {
+ max_keep--;
+ continue;
+ }
+ deleteGeneration2(profile, i->number, dryRun);
+ }
+}
void deleteOldGenerations(const Path & profile, bool dryRun)
{
diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh
index 1d4e6d303..3cad08dc5 100644
--- a/src/libstore/profiles.hh
+++ b/src/libstore/profiles.hh
@@ -39,6 +39,8 @@ void deleteGeneration(const Path & profile, unsigned int gen);
void deleteGenerations(const Path & profile, const std::set & gensToDelete, bool dryRun);
+void deleteGenerationsGreaterThan(const Path & profile, const string & max, bool dryRun);
+
void deleteOldGenerations(const Path & profile, bool dryRun);
void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun);
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index 97e66cbd9..1440b7744 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -1284,6 +1284,8 @@ static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opAr
deleteOldGenerations(globals.profile, globals.dryRun);
} else if (opArgs.size() == 1 && opArgs.front().find('d') != string::npos) {
deleteGenerationsOlderThan(globals.profile, opArgs.front(), globals.dryRun);
+ } else if (opArgs.size() == 1 && opArgs.front().find('+') != string::npos) {
+ deleteGenerationsGreaterThan(globals.profile, opArgs.front(), globals.dryRun);
} else {
std::set gens;
for (auto & i : opArgs) {