Generate and Inspect a Debian .changes File with dpkg-genchanges
You will produce a Debian .changes upload manifest from an unpacked, built source tree, then check which files and metadata it contains. Allow about 15 minutes if the package has already been built. This guide uses the installed dpkg-dev version 1.22.6ubuntu6.6, so confirm your own version before relying on a detail in a build script.
The route
Jump straight to the step you need, or tick off Done means at the end.
The command generates metadata for an upload. It does not upload anything, sign the result, or install a package. You normally run it as the package maintainer in the package's build area, without sudo.
1. Check the installed command and package
Start by confirming that the command comes from the expected package. This catches a missing development package and makes later troubleshooting less vague.
$ command -v dpkg-genchanges
/usr/bin/dpkg-genchanges
$ dpkg-query -W -f='${Package} ${Version}\n' dpkg-dev
dpkg-dev 1.22.6ubuntu6.6
$ dpkg-genchanges --version
Debian dpkg-genchanges version 1.22.6
Your version may differ. The installed manual documents --build and -O as available since dpkg 1.18.5, and the package shown above supports both.
Checkpoint
Continue only if command -v finds the binary and the reported package is the dpkg-dev installation you intend to use.
2. Inspect the inputs before generating anything
dpkg-genchanges reads the source tree's control and changelog files, and reads the list of upload files from debian/files by default. The default control path is debian/control, the default changelog path is debian/changelog, and the default files-list path is debian/files.
$ test -r debian/control && echo 'control: readable'
control: readable
$ test -r debian/changelog && echo 'changelog: readable'
changelog: readable
$ test -r debian/files && echo 'files list: readable'
files list: readable
$ sed -n '1,80p' debian/files
Each entry in debian/files identifies a generated file and its section and priority. The files must exist where the command looks for them. By default, that upload directory is the parent directory, .., not the package directory itself. If your build puts artefacts elsewhere, use -u later rather than moving files blindly.
Do not edit debian/files to hide a failed or unreviewed build. Fix the build output or regenerate the list through your normal Debian packaging workflow.
3. Choose the upload contents explicitly
The default build type is full, which includes source, architecture-specific binary packages and architecture-independent binary packages. Make that choice visible in a repeatable command:
$ dpkg-genchanges --build=full -O> ../demo_0.1-1_full.changes
The -O option writes the changes file to standard output when used without a filename. Here the shell redirects it to a new file. The command also writes its informative messages to standard error, so a message about the number of source files does not corrupt the control file.
Use a narrower type when that is what the archive upload requires:
--build=sourceor-Sfor source files only.--build=anyor-Bfor architecture-specific binaries.--build=allor-Afor architecture-independent binaries.--build=binaryor-bfor both binary categories.--build=source,allor-gfor source and architecture-independent files.--build=source,anyor-Gfor source and architecture-specific files.
For source uploads, -si is the default source selection: the original source archive is included when the upstream version differs from the previous changelog entry. Use -sa to force its inclusion or -sd to exclude it and include only the diff. Do not choose these flags by habit, because the resulting file list affects what you publish.
Checkpoint
Write down the one build type you want. If you cannot explain why a source archive or a binary architecture is included, stop and inspect the build result first.
4. Generate into a new file
Use a new destination while testing. Shell redirection with > truncates an existing destination before dpkg-genchanges has succeeded, so do not point it at a changes file you may still need.
$ output='../demo_0.1-1_full.changes.new'
$ dpkg-genchanges --build=full -O> "$output"
$ status=$?
$ printf 'dpkg-genchanges status: %s\n' "$status"
dpkg-genchanges status: 0
$ test -s "$output" && echo 'changes file: non-empty'
changes file: non-empty
If the status is non-zero, keep the diagnostic from standard error and do not rename the partial file. Once you have reviewed the output, replace a prior file deliberately:
$ mv --no-clobber ../demo_0.1-1_full.changes.new ../demo_0.1-1_full.changes
mv: ...
--no-clobber refuses to replace an existing destination. If it reports that the destination exists, inspect both files and choose a different name or remove the old file only after confirming it is disposable. Removing the old upload manifest is irreversible; it does not remove the package artefacts, but it does remove a useful record of their checksums.
5. Read the generated control data
A .changes file is Debian control data in deb822 format. Check the fields that determine what an archive tool will understand:
$ sed -n '1,120p' ../demo_0.1-1_full.changes
Format: 1.8
Date: Wed, 23 Sep 2026 10:00:00 +0000
Source: demo (0.1-1)
Binary: demo
Architecture: all source
Version: 0.1-1
Distribution: unstable
Urgency: low
Maintainer: Demo <[email protected]>
Changes:
demo (0.1-1) unstable; urgency=low
.
* Fixture for checking dpkg-genchanges.
Files:
...
Exact dates, checksums, package names and continuation lines depend on your source tree. Required fields include Format, Date, Source, Version, Distribution, Maintainer, Changes, Files, Checksums-Sha1 and Checksums-Sha256. A binary upload normally also has Binary; a source-only upload can omit it.
Compare the filename and size in Files with the two checksum lists. The three lists must describe the same upload files. The legacy Files field uses MD5 and also includes section and priority; the SHA-1 and SHA-256 fields use checksum, size and filename. That difference is part of the format, not a reason to edit the generated file by hand.
6. Troubleshoot without escalating privileges
A missing file error usually means that debian/files names an artefact in the wrong directory, or that the build did not produce it. Check both sides:
$ sed -n '1,120p' debian/files
$ while read -r name section priority; do
> test -e "../$name" || printf 'missing: ../%s\n' "$name"
> done < debian/files
If the files are in a separate directory, pass it explicitly:
$ dpkg-genchanges --build=full -u../build-output -O> ../demo_0.1-1_full.changes.new
Use -c, -l or -f only when your package deliberately stores its control, changelog or file list at a non-default path. Use -DField=value to add or override an output field and -UField to remove one, but treat those as packaging changes that deserve review. Never use them to conceal an incorrect distribution, version or maintainer.
Run as an ordinary user. sudo dpkg-genchanges can create root-owned output and can mask a permission problem that a build service will still have. No service is restarted and no package database is changed by this command.
Done means
- You confirmed the installed
dpkg-devversion and command path. - You checked
debian/control,debian/changeloganddebian/files. - You selected an explicit build type that matches the intended upload.
- The generated file is non-empty and was written to a new destination.
- You inspected the deb822 fields, filenames, sizes and matching checksum lists.
- You can recover from a missing artefact without using elevated privileges or overwriting the previous manifest.