Bisecting is a feature of version control systems such as Git and Mercurial to easily pinpoint regressions. Owing to their reproducibility, Nix and NixOS are well-suited to this. As a result, there are a few common use-cases for Nix.
(If you don't have git available, you can make it available in a shell using:)
nix --extra-experimental-features 'nix-command flakes' shell nixpkgs#gitgit bisect start $BAD $GOOD && git bisect run $CMDeither:
- nix-bisect: smartly pick
bisect bad/skipin automated bisects and give nicer outputs - hydrasect: prioritize cached commits in nixpkgs bisects - unfortunately still lacks nix package/flake
- after each checkout run
git checkout $(hydrasect-search | head -1)
- after each checkout run
- nixpkgs-staging-bisecter: like hydrasect but minimize how many derivations you will build even in staging
- run in
nixpkgsrepo, e.g. forsignal-desktop:
cat >> .test<< EOF
#! /usr/bin/env bash
$(nix-build -A signal-desktop)/bin/signal-desktop --use-tray-icon --no-sandbox
EOF
chmod +x ./test
git bisect start -- pkgs/applications/networking/instant-messengers/signal-desktop/
git bisect bad
git bisect run sh -c './test; [ $? -eq 0 ]'Place bisect.sh in the system repo, then from there run:
chmod +x ./bisect.sh
git stash push flake.lockFrom the dependency's repo, run steps like:
git bisect start $BAD $GOOD
export SYSTEM_REPO=/etc/nixos
export DEPENDENCY_INPUT=$(basename $PWD) # e.g. nixpkgs
export DEPENDENCY_URL=https://github.com/NixOS/nixpkgs # exampleThen, if judgement needs manual intervention, run cycles of:
$SYSTEM_REPO/bisect.sh $DEPENDENCY_INPUT $DEPENDENCY_URL $SYSTEM_REPO
# git checkout $(hydrasect-search | head -1) # only if the dep is nixpkgs
# <TEST>
git bisect good
git bisect badOr, if judgement can be automated (COMMAND optional, will rebuild):
git bisect run $SYSTEM_REPO/bisect.sh $DEPENDENCY_INPUT $DEPENDENCY_URL $SYSTEM_REPO && <COMMAND>
bisecting these is non-trivial given how long this can take -
esp given for mastodon for one it doesn't seem to be the sole commit updating the mastodon version that broke itupdate it did cause the ViteMissingExecutableError.reducing rebuilds may need a combination of bisecting tools:
hydrasect: for the initial part of the bisect where hydra-cached commits are available, helps identify those commits (git checkout $(hydrasect | head -1)) to prevent local builds.nixpkgs-staging-bisecter: for the later part of bisects, when hydra-cached commits are no longer available,--dry-runs hard to check out a cheap commit to test (bisecter.py --checkout nix-build ...) while minimizing rebuilds.nix-bisect: helps better judge outcome (git bisect'sgoodvsbad/skip) and gives nicer outputs thangit bisect run.bisect-env --try-pick REV CMD ARGS: runs command with cherry-picks.extra-bisect:runskips on command failure (125) / user exit (129),envpasses thru tobisect-envwith existing patchsets (but no cherry-picks).nix-build-status: lazily determine the status of anix-instantiatein a bisect-friendly format. args:drvish/--file=./--failure-line=None.this could be achieved like e.g.:
such a script depends on various questions:
DEP_NAME: what is the dependency's alias in the project to be built?DEP_DIR: what is the root directory (for the purpose of version control) of the dependency?nix-bisect/bin/extra-bisectgets--flake. further implies different ways of overriding the dependency, if applicable, as per above:export NPINS_OVERRIDE_${DEP_NAME | snake_case}=${DEP_DIR}+--argstr impure truefornpins, vs.--override-input "${DEP_NAME}" "${DEP_DIR}"for flakes)nixpkgs? (if yes, usenixpkgs-staging-bisecter, as well asgit bisect start's--first-parent- if not alsohydrasectas implied by hydra builds for caching, see below.)does the project to be bisected use hydra builds for caching? (implied by e.g.- just supportsnixpkgsfrom above - if yes, usehydrasect(including precedinghydrascrape).)nixpkgsso far.ATTR_PATH+=.system.build.toplevel)nix-bisect/bin/extra-bisectgets--on-dependency-failure bad)bisect-envwith a--try-pick <commit>per commit to be cherry-picked)BUILD_DIR: what is the path to the directory containing the entrypoint of the failing build?ATTR_PATH: what is the attribute path (i.e. may contains.s) of the failing dependency?what version control system is used by the project to bisect? (e.g. git, ... - git is needed fornix-bisect,hydrasect,nixpkgs-staging-bisecter, if not also by--first-parent. git is implied by bisectingnixpkgsor anything withfetch-treeschemegit/github/gitlab/sourcehut.)BAD: what is the (oldest) known revision failing due to the regression?GOOD: what is the (newest) known revision that succeeded, so before the regression?FAILURE_LINE: what error line would identify the build failure?NIXPKGS_STAGING_BISECTER_PY: where is yournixpkgs-staging-bisecterpython script located? (e.g.$(nix-instantiate --eval --raw '(import <nixpkgs> { }).callPackage (builtins.fetchTree "github:KiaraGrouwstra/nixpkgs-staging-bisecter?branch=default-nix").outPath { }')/bin/nixpkgs-staging-bisecter)