Updating Ubuntu packages that you have local changes for with dgit
Suppose, not entirely hypothetically, that you've made local changes to an Ubuntu package using dgit and now Ubuntu has come out with an update to that package that you want to switch to, with your local changes still on top. Back when I wrote about moving local changes to a new Ubuntu release with dgit, I wrote an appendix with a theory of how to do this, based on a conversation. Now that I've actually done this, I've discovered that there is a minor variation and I'm going to write it down explicitly (with additional notes because I forgot some things between then and now).
I'll assume we're starting from an existing dgit based repository with a full setup of local changes, including an updated debian/changelog. Our first step, for safety, is to make a branch to capture the current state of our repository. I suggest you name this branch after the current upstream package version that you're on top of, for example if the current upstream version you're adding local changes to can be summarized as 'ubuntu2.6':
git branch cslab-2.6
Making a branch allows you to use 'git diff cslab-2.6..' later to
see exactly what changed between your versions. A useful thing to
do here is to exclude the 'debian/' directory from diffs, which can
be done with 'git diff cslab-2.6.. -- . :!debian', although
your shell may require you to quote the '!' (cf).
Then we need to use dgit to fetch the upstream updates:
dgit fetch -d ubuntu
We need to use '-d ubuntu', at least in current versions of dgit, or 'dgit fetch' gets confused and fails. At this point we have the updated upstream in the remote tracking branch 'dgit/dgit/jammy,-security,-updates' but our local tree is still not updated.
(All of dgit's remote tracking branches start with 'dgit/dgit/', while all of its local branches start with just 'dgit/'. This is less than optimal for my clarity.)
Normally you would now rebase to shift your local changes on top
of the new upstream, but we don't want to immediately do that. The
problem is that our top commit is our own dgit-based change to
debian/changelog, and we don't want to rebase that commit; instead
we'll make a new version of it after we rebase our real local
changes. So our first step is to discard our top commit:
git reset --hard HEAD~
(In my original theory I didn't realize
we had to drop this commit before the rebase, not after, because
otherwise things get confused. At a minimum, you wind up with
debian/changelog out of order, and I don't know if dropping your
HEAD commit after the rebase works right. It's possible you might
get debian/changelog rebase conflicts as well, so I feel dropping
your debian/changelog change before the rebase is cleaner.)
Now we can rebase, for which the simpler two-argument form does work (but not plain rebasing, or at least I didn't bother testing plain rebasing):
git rebase dgit/dgit/jammy,-security,-updates dgit/jammy,-security,-updates
(If you are wondering how this command possibly works, as I was part way through writing this entry, note that the first branch is 'dgit/dgit/...', ie our remote tracking branch, and then second branch is 'dgit/...', our local branch with our changes on it.)
At this point we should have all of our local changes stacked on top of the upstream changes, but no debian/changelog entry for them that will bump the package version. We create that with:
gbp dch --since dgit/dgit/jammy,-security,-updates --local .cslab. --ignore-branch --commit
Then we can build with 'dpkg-buildpackage -uc -b', and afterward do 'git clean -xdf; git reset --hard' to reset your tree back to its pristine state.
(My view is that while you can prepare a source package for your work if you want to, the 'source' artifact you really want to save is your dgit VCS repository. This will be (much) less bulky when you clean it up to get rid of all of the stuff (to be polite) that dpkg-buildpackage leaves behind.)