An Overview
This guide provides a detailed walkthrough of various rollback methods in NixOS, emphasizing the integration of Git for robust configuration management. It covers:
- Traditional NixOS Rollback: Using GRUB/systemd boot menus and the
switch-to-configuration
tool. - Git-Based Rollback for Configuration Files: Tracking changes with Git, using
git revert
for undoing commits, andgit reset
for more forceful reversions. - Rollback of Nix Channels: Understanding channel generations, utilizing
nix-channel --rollback
, and differentiating between user-level and root-level channels. - Garbage Collection: Employing
nix-collect-garbage
for storage management, understanding the implications for rollback (--delete-older-than
), and the inherent risks of deleting past generations. - The Power of NixOS Flakes: Exploring how flakes, with their
flake.nix
andflake.lock
files, revolutionize rollback and version control. - Infinite Rewind with Flakes: Understanding how the
flake.lock
file, by recording precise package versions, enables rollback to any point in your Git history, even after garbage collection. - Unified Rollback with Flakes: Using
git revert
to handle both configuration changes and package version rollbacks when using flakes. - Managing Your NixOS Configuration with Git: A detailed walkthrough of setting up and utilizing Git for your NixOS configuration files.
Traditional NixOS Rollback Mechanisms
Leveraging Boot Menus
When a NixOS system fails to boot or encounters issues after a configuration change or package update, the most immediate recourse is the boot menu. Both GRUB and systemd boot menus typically retain entries for several previous system generations. Selecting a prior working generation from the boot menu allows you to quickly restore a functional system state.
The switch-to-configuration
Tool
While booting into a previous generation provides immediate recovery, it doesn’t alter the default boot entry. Subsequent reboots would default to the potentially broken configuration. The switch-to-configuration
tool addresses this.
- Location:
/run/current-system/sl-bin/switch-to-configuration
- Usage:
sudo switch-to-configuration [option]
- Options resemble those of
sudo nixos-rebuild
:switch
,boot
,test
, etc.
Running sudo switch-to-configuration boot
after booting into a working older generation sets that generation as the default, ensuring future reboots default to the known good state.
Git-Based Configuration Management
Tracking Changes with Git
Version controlling your NixOS configuration files with Git is essential for reliable rollback and configuration management.
-
Initialization: Navigate to your configuration directory (e.g.,
~/dotfiles
) and rungit init
. -
Configuration: Configure Git with your name and email:
git config --global user.name "Your Name" git config --global user.email "you@example.com"
-
First Commit: Stage all changes (
git add .
) and make your initial commit:git commit -m "Initial commit"
Reverting Configuration Changes with git revert
When a configuration change introduces issues, git revert
provides a safe method to undo specific commits.
-
Identify the Problematic Commit: Use
git log
to review commit history and locate the commit hash responsible for the problem. -
Revert the Commit:
git revert <commit-hash>
This creates a new commit that undoes the changes introduced by the specified commit.
Using git reset
for More Forceful Reversions
In situations where you need to discard all changes since a particular commit, git reset
offers a more potent solution.
Caution: git reset --hard
permanently removes changes. Use with extreme care!
git reset --hard <commit-hash>
This resets your branch to the specified commit, discarding all subsequent commits.
Rollback of Nix Channels
Understanding Channel Generations
NixOS channels represent snapshots of the Nixpkgs repository, dictating the available package versions. Updating channels (nix-channel --update
) fetches newer generations, potentially introducing breaking changes.
Rolling Back Channels
The nix-channel --rollback
command enables reverting to older channel generations.
-
List Generations:
nix-channel --list-generations
This displays available generations, with the most recent at the top.
-
Rollback:
nix-channel --rollback <generation-number>
User vs. Root Channels
NixOS maintains separate channel sets for regular users and the root user. Ensure you’re manipulating the correct channel set (using sudo
for root) when rolling back.
Garbage Collection and Its Impact on Rollback
Freeing Up Storage with nix-collect-garbage
Over time, the Nix store accumulates older package versions, consuming significant storage. The nix-collect-garbage
command reclaims space by deleting unused generations.
Cautious Garbage Collection
Important: Garbage collection removes past system states, making rollbacks to those states impossible.
-
Safer Approach:
nix-collect-garbage --delete-older-than 30d
This deletes generations older than 30 days, preserving recent rollback points.
-
Risky Approach (
--delete-old
): Deletes all unused generations, severely limiting rollback options. Use with extreme caution!
NixOS Flakes: A Paradigm Shift in Rollback
The flake.lock
File: Precise Version Control
Traditional NixOS rollbacks rely on preserving system generations. Flakes, through the flake.lock
file, introduce a superior approach. This file records the exact Git revisions of all dependencies used in your system, enabling precise recreation of past configurations.
Benefits of flake.lock
- Complete Reproducibility: Build identical system configurations even after garbage collection.
- Historical Rollback: Revert to any point in your Git history, restoring both configuration and specific package versions.
- Space Efficiency: No need to retain numerous system generations for rollback purposes.
Unified Rollback with git revert
With flakes, rolling back configuration changes and package versions becomes a unified process using git revert
. Simply revert the commit that introduced the changes, and your flake.lock
file will ensure the system is restored to its precise prior state.
Managing Your NixOS Configuration with Git (Detailed)
Setting Up a Git Repository
-
Choose a Location: Designate a directory to house your configuration files (e.g.,
~/dotfiles
). -
Initialize the Repository:
git init
-
Configure Git (Mandatory):
git config --global user.name "Your Name" git config --global user.email "you@example.com"
-
Set Default Branch (Recommended): To avoid potential conflicts with remote repositories:
git config --global init.defaultBranch main
Handling Configurations Owned by Root
If your configuration files reside under /etc/nixos
(owned by root), you’ll need to adjust permissions for seamless Git integration as a regular user.
-
Create the
.git
Directory as Root:sudo mkdir /etc/nixos/.git
-
Change Ownership to Your User:
sudo chown -R $USER:$USER /etc/nixos/.git
-
Initialize the Repository:
git init
-
Add Safe Directory:
git config --global --add safe.directory /etc/nixos
This informs Git that the directory is managed by you, preventing warnings about ownership.
Staging, Committing, and Pushing Changes
-
Stage Changes: Use
git add <file>
to stage specific files orgit add .
for all changes. -
Commit Changes:
git commit -m "Descriptive commit message"
-
Set Up a Remote Repository: Choose a hosting service (GitHub, GitLab, etc.) and create an empty repository.
-
Connect Your Local Repository to the Remote:
git remote add origin <remote-repository-url>
-
Push Changes:
git push origin main
Replace
main
with your default branch name if different.
Restoring Your Configuration on a New System
-
Clone the Repository:
git clone <remote-repository-url>
-
Rebuild Your System: Follow the standard NixOS procedures to apply your configuration.
Common Gotchas and Solutions
- Unstaged Changes: NixOS detects unstaged changes in your Git repository. Ensure you’ve staged (
git add
) all new or modified files before rebuilding your system to avoid errors.
Advanced Git Integration with NixOS Flakes
Running Scripts and Software Directly from Git
Leveraging flakes, you can execute scripts or software directly from your Git repository without explicit installation.
Understanding the Mechanism
packages
Output inflake.nix
: Declare packages or scripts as applications, specifying runtime dependencies usingruntimeInputs
.apps
Output inflake.nix
: Define how these applications should be invoked.nix run
Command: Execute applications defined in your flake.
Setting Up Direct Execution
-
Define
packages
andapps
Outputs: Follow the structure outlined in source, adjusting names, scripts, and dependencies as needed. -
Ensure Git is Available: On a fresh NixOS system, Git might not be installed by default. You can use
nix-shell -p git
to enter a shell with Git. -
Run from Git:
nix run github:username/repository#appName
- Replace
github:username/repository
with your Git repository information. - Replace
appName
with the name defined in yourapps
output.
- Replace
Example:
nix run github:LibrePhoenix/nix-config#install
Note: This example assumes you have a repository named nix-config
on GitHub under the username LibrePhoenix
and an application named install
defined in your flake outputs.
Benefits
- Single-Command Installation: Streamline the setup process on new machines.
- Dependency Management: Automatically handle runtime dependencies.
- Simplified Distribution: Share and deploy configurations easily.
Conclusion
Mastering rollback mechanisms and configuration management is crucial for a smooth NixOS experience. While traditional methods offer immediate recovery and basic version control, embracing Git and the power of NixOS flakes unlocks a new level of reproducibility, flexibility, and control over your system configuration.