Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

input-branches

While we wait for (or contribute towards) a Nix feature of seamless application of pathces to a flake input, this project defines a worflow for application of patches to an imported git branch and provides commands that support this workflow via flake-parts options.

Costs:

  • πŸ€Ήβ€β™‚οΈ some mental and operational git related overhead

  • 🎈 increase in the repository's size due to storage of foreign objects

  • πŸ”– limits the types a flake can be fetched as to only Git

Benefits:

  • 🐬 single-repo setup; more self-contained, less to keep track of

  • πŸ’ƒ no artificial committing/pushing during development

  • πŸ•Ί no typing --override-input and no accidentally omitting it

  • ⚑ provided scripts save time and improve consistency

The workflow

A Flake input is commonly a branch in a git repository (even if used as type github or similar). Assuming we lack the freedom to add commits to that upstream branch, we can clone the upstream repository, maintain a branch with our commits on top and rebase it on the upstream branch at some frequency. That works, but it incurs some costs. For one, our project spans across one more repository. But creating a new repository is not necessary. We can import the upstream branch into our project's repository. For example, if the upstream branch is Nixpkgs' nixpkgs-unstable then we can import it as inputs/nixpkgs in our repository.

note

With some repositories one might hit push limits such as GitHub's. That is the case with a recent Nixpkgs.

Now our project spans across one branch more.

The Nix CLI's --override-inputs flag allows explicit invocations to be attempted with a temporary substitute for a particular input. That seems appropriate in many cases. With this workflow that flag is not necessary.

An input url points at a path inside the repository:

inputs.nixpkgs.url = "./inputs/nixpkgs";

and at that path is our project repository nested within itself as a Git submodule in which the inputs/nixpkgs branch (or its detached HEAD) is checked out. .gitmodules should have such lines:

[submodule "inputs/nixpkgs"] path = inputs/nixpkgs url = ./.

This setup allows us to edit the input within the local repository clone during development and execute Nix flake commands without --override-input.

important

If the superproject state is clean, submodules will be fetched instead of used by path. Workaround: $ touch dirt; git add -N dirt This was reported as issue 13324.

When our flake is fetched remotely, Nix detects the submodule and fetches its HEAD.

note

Our flake can now be fetched only using Git (e.g. no github: or similar) and with submodules enabled, for example:

$ nix flake show "git+https://example.com/repo?submodules=1&shallow=1"

tip

Since our project now depends on multiple branches make sure that in addition to pushing the regular branches input branches are pushed as well.

tip

Be careful that tools such as linters and formatters exclude the path ./inputs.

NixOS impurity

By default NixOS uses git metadata in some derivations. That might not be a problem when Nixpkgs is a "normal" input. But when Nixpkgs is a path type input then the git metadata is no longer of the Nixpkgs repository but of the parent repository. That is unintended behavior and results in unexpected change to NixOS derivations.

A NixOS module provided by this flake disables these impurities at the cost of the absence of some version information. It is available as #modules.nixos.pure.

Installation

To use these options, add to your flake inputs:

input-branches.url = "github:mightyiam/input-branches";

and inside the mkFlake:

imports = [ inputs.input-branches.flakeModules.default ];

Run nix flake lock and you're set.

Options

input-branches.baseDir

Directory relative to Git top-level for git submodules.

Type: string (read only)

Default: "inputs"

Declared by:

input-branches.inputs

Input branch definitions. Each attribute name must correspond to an existing flake input.

Type: lazy attribute set of (submodule)

Default: "{ }"

Example:

{ nixpkgs.upstream = { url = "https://github.com/NixOS/nixpkgs.git"; ref = "nixpkgs-unstable"; }; home-manager.upstream = { url = "https://github.com/nix-community/home-manager.git"; ref = "master"; }; }

Declared by:

input-branches.inputs.<name>.branch

input branch name

Type: string (read only)

Default: inputs/<name>

Declared by:

input-branches.inputs.<name>.name

Name of input. A flake input by this name must exist.

Type: string (read only)

Default: <name>

Example: "flake-parts"

Declared by:

input-branches.inputs.<name>.path_

path of submodule relative to Git top-level

Type: string (read only)

Default: inputs/<name>

Declared by:

input-branches.inputs.<name>.upstream.name

remote upstream name

Type: string (read only)

Default: "upstream"

Declared by:

input-branches.inputs.<name>.upstream.ref

ref of the upstream Git repo

Type: string

Example: "master"

Declared by:

input-branches.inputs.<name>.upstream.url

remote URL of the upstream Git repo

Type: string

Example: "https://github.com/nix-community/stylix.git"

Declared by:

perSystem.input-branches.commands.all

a list of all of the commands, for convenience

Type: list of package (read only)

Declared by:

perSystem.input-branches.commands.init

A list of input-branch-init-<INPUT> commands that attempt to initialize INPUT. For example:

$ input-branch-init-nixpkgs

And you end up with a git submodule at the configured path. It inherited the remote of the remote tracking branch of the current branch. It has an upstream remote according to configuration. The configured branch is checked out and its HEAD set to the rev that the corresponding flake input is locked to. The input url can be set to use it:

{ inputs.flake-parts.url = "./inputs/nixpkgs"; }

With some repositories one might hit push limits such as GitHub’s. That is the case with a recent Nixpkgs. Pushing is the last action this command takes, so if that fails you can step into the directory and try pushing in chunks.

Type: list of package (read only)

Declared by:

perSystem.input-branches.commands.push-force

a list of input-branch-push-force-<INPUT> commands that push with --force the configured branch of INPUT

Type: list of package (read only)

Declared by:

perSystem.input-branches.commands.rebase

a list of input-branch-rebase-<INPUT> commands that attempt to rebase INPUT

Type: list of package (read only)

Declared by: