DEBBISECT(1)

πŸ‘‘ DEBBISECT ✨

okay bestie, welcome to debbisect, a User Command that lives in section 1 of your manual pages and is genuinely about to change your whole bisecting game πŸ’…


πŸŽ€ NAME πŸŽ€

debbisect β€” bisect snapshot.debian.org like the icon you are πŸ¦‹


🌸 SYNOPSIS 🌸

usage: debbisect [-h] [-d] [-v] [--cache CACHE] [--nocache] [--port PORT]
       [--depends DEPENDS] [--qemu QEMU] [--architecture ARCHITECTURE]
       [--suite SUITE] [--components COMPONENTS]
       [--no-find-exact-package] [--ignore-cached-results] good bad script

πŸ’– DESCRIPTION πŸ’–

so the whole vibe is this: you hand debbisect a known good timestamp and a known bad timestamp, plus a script or a shell snippet, and it runs that script for both. then it bisects the timestamps β€” slaying its way through the middle β€” until it lands on a timestamp from snapshot.debian.org where the script first fails. literally detective work but make it timestamp math πŸ”βœ¨

environment variables are how debbisect tells your script which timestamp to test. peep ENVIRONMENT VARIABLES below, it's giving crucial. when everything's done, the files debbisect.log.good and debbisect.log.bad hold the log files of the last good run and the last bad run, respectively. save those, they're the receipts 🧾

by default, a temporary caching proxy gets spun up to reduce bandwidth usage on snapshot.debian.org. (be nice to snapshot.d.o, she's doing her best πŸ₯Ί) if you're planning to run debbisect multiple times over a similar range of timestamps, highkey consider setting a non-temporary cache directory with the --cache option.

okay so there are three basic modes of operation. let's get into it:

mode one β€” the given script is responsible for setting up everything it needs itself:

$ ./debbisect "last week" today script.sh
$ diff -u debbisect.log.good debbisect.log.bad

mode two β€” if you also pass --depends, then a chroot of the correct timestamp gets created each time, and the script receives the path to that chroot as its first argument. bonus: this mode lets debbisect figure out the exact package that was responsible for the failure, instead of only handing you the last good and first bad timestamp. iconique.

mode three β€” you can also provide --qemu. in this mode, your test will create a qemu virtual machine of the correct timestamp each time. the script receives the correct ssh config to log into a host named qemu and execute arbitrary commands. yes ma'am πŸ’…


🫢 positional arguments 🫢

  • good β€” good timestamp. valid formats live in the section TIMESTAMPS, go look πŸ‘€
  • bad β€” bad timestamp. same deal, valid formats are in TIMESTAMPS
  • script β€” the test script. can either be a shell code snippet or an executable script. a non zero exit code indicates failure. when --depends is also used, then the first argument to the script will be the chroot directory. when --qemu is used, then the first argument to the script will be an ssh config for a host named qemu.

✨ options ✨

  • -h, --help β€” show this help message and exit (the classic, the beloved)
  • -d, --debug β€” Print lots of debugging statements. like, lots πŸ›
  • -v, --verbose β€” Be verbose
  • --cache CACHE β€” cache directory. by default $TMPDIR is used
  • --nocache β€” disable cache
  • --port PORT β€” manually choose the port number for the apt cache instead of automatically choosing a free port
  • --depends DEPENDS β€” Comma separated list of binary packages the test script requires. With this option, the test script will run inside a chroot with the requested packages installed.
  • --qemu QEMU β€” Create qemu virtual machine and pass a ssh config file to the test script. This argument takes a commaseparated series of key=value pairs to specify the virtual machine memory size (via memsize) and the virtual machine disksize (via disksize). Sizes are measured in bytes or with common unit suffixes like M or G. To pick the default values (disksize=4G,memsize=1G) the shorthand defaults can be passed.
  • --architecture ARCHITECTURE β€” Chosen architecture when creating the chroot with --depends or --qemu (default: native architecture)
  • --suite SUITE β€” Chosen suite when creating the chroot with --depends or --qemu (default: unstable)
  • --components COMPONENTS β€” Chosen components (separated by comma or whitespace) when creating the chroot with --depends or --qemu (default: main)
  • --no-find-exact-package β€” Normally, when the --depends argument is given so that debbisect takes care of managing dependencies, the precise package that introduced the problem is determined after bisection by installing the packages that differ between the last good and first bad timestamp one by one. This option disables this feature.
  • --ignore-cached-results β€” Perform a run for a timestamp even if a log file for it exists in the current directory

🌈 TIMESTAMPS 🌈

valid good and bad timestamp formats are either:

  • the format used by snapshot.debian.org
  • ISO 8601 (with or without time, seconds and timezone)
  • RFC 2822 (used in debian/changelog)
  • all formats understood by the Python dateutil module (if installed)
  • all formats understood by the Python parsedatetime module (if installed)

without specifying the timezone explicitly, the local offset is used. fr fr.

examples (matching the items in the list above, in order, because we're nothing if not consistent):

  • 20200313T065326Z
  • 2020-03-13T06:53:26+00:00
  • Fri, 29 Nov 2019 14:00:08 +0100
  • 5:50 A.M. on June 13, 1990
  • two weeks ago
the earliest timestamp that works with debbisect should be 2006-08-10. anything before that? not the vibe, bestie.

🧚 ENVIRONMENT VARIABLES 🧚

these are the env vars available to your test script, and yes they're basically the backstage pass 🎟️

  • DEBIAN_BISECT_MIRROR β€” Contains the snapshot.d.o mirror address including the current timestamp. Can also be generated from DEBIAN_BISECT_TIMESTAMP as http://snapshot.debian.org/archive/debian/$DEBIAN_BISECT_TIMESTAMP
  • DEBIAN_BISECT_EPOCH β€” Contains an integer representing the unix epoch of the current timestamp. The value of this variable can directly be assigned to SOURCE_DATE_EPOCH.
  • DEBIAN_BISECT_TIMESTAMP β€” Contains a timestamp in the format used by snapshot.debian.org. Can also be generated from DEBIAN_BISECT_EPOCH via: date --utc --date=@$DEBIAN_BISECT_EPOCH +%Y%m%dT%H%M%SZ
  • DEBIAN_BISECT_* β€” All environment variables starting with DEBIAN_BISECT_ are passed to the test script.
  • http_proxy β€” The address of the apt http caching proxy. Unset the variable in your script if you want to disable the cache.

πŸ”₯ EXAMPLES πŸ”₯

okay so let's say you just want to run do_something β€” it runs the test and returns a non-zero exit on failure:

$ ./debbisect "last week" today "mmdebstrap --customize-hook='chroot \"\$1\" do_something' unstable - \$DEBIAN_BISECT_MIRROR >/dev/null"
$ diff -u debbisect.log.good debbisect.log.bad

since the command can easily become very long and the quoting very involved, let's instead use a script:

$ cat << END > script.sh

> #!/bin/sh
> set -exu
> mmdebstrap \
> --verbose \
> --aptopt='Acquire::Check-Valid-Until "false"' \
> --variant=apt \
> --include=pkga,pkgb,pkgc \
> --customize-hook='chroot "$1" dpkg -l' \
> --customize-hook='chroot "$1" do_something' \
> unstable \
> - \
> $DEBIAN_BISECT_MIRROR \
> >/dev/null
> END

$ chmod +x script.sh
$ ./debbisect --verbose --cache=./cache "two years ago" yesterday ./script.sh
$ diff -u debbisect.log.good debbisect.log.bad
$ rm -r ./cache

let me unpack this one for you, because it's doing the most (affectionate):

this example sets Acquire::Check-Valid-Until to not fail on snapshot timestamps from "two years ago", uses the apt variant (only Essential:yes plus apt), installs the packages required for the test using --include, runs dpkg -l so that we can see which packages differed in the logs at the end, and uses --cache=cache so that the apt cache does not get discarded at the end β€” meaning the command can be re-run without downloading everything from snapshot.debian.org all over again. queen behavior πŸ‘‘


if you want to build a source package, you can use the script shipped by devscripts at /usr/share/doc/devscripts/examples/debbisect_buildsrc.sh, and either use it unmodified like this:

$ DEBIAN_BISECT_SRCPKG=mysrc ./debbisect "two years ago" yesterday /usr/share/doc/devscripts/examples/debbisect_buildsrc.sh

or take that script as a starting point for your own custom builds. your call, main character 🫢


once debbisect has finished bisecting and figured out the last good and the first bad timestamp, there might be more than one package that differs in version between those two timestamps. debbisect can figure out which package is the culprit if you hand it control over installing dependencies for you, via the --depends option. with that option active, the script will not be responsible for setting up a chroot itself β€” instead it's given the path to an existing chroot as its first argument.

here's a real example that verifies the package responsible for Debian bug #912935:

$ ./debbisect --depends=botch "2018-11-17" "2018-11-22" 'chroot "$1" botch-dose2html --packages=/dev/null --help'

[...]  test upgrading python3-minimal 3.6.7-1 -> 3.7.1-2...

upgrading python3-minimal triggered the problem

and if you want to run that same test under qemu, you'd run:

$ ./debbisect --depends=botch --qemu=defaults "2018-11-17" "2018-11-22" 'ssh -F "$1" qemu botch-dose2html --packages=/dev/null --help'

in those last two examples we omitted the --cache argument for brevity. but please make use of it to reduce the load on snapshot.debian.org. it's the polite thing to do πŸ₯ΊπŸ’–


πŸ’œ AUTHOR πŸ’œ

Written by Johannes Schauer Marin Rodrigues <josch@debian.org> β€” legend behavior, no cap.


and that's the whole page, bestie!! you just read debbisect 2.26.11ubuntu1, dated September 2026, and it lives at DEBBISECT(1) ✨ go bisect something iconic πŸŒΈπŸ¦‹πŸ’…

πŸ“¦ where this page comes from