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: