My preferred answer is that it is a constantly rebasing branch topped with a series of pseudomerges to make it fast-forwarding. ------/--A!----/--B3!--%--/--> interchange view / / / with debian/ directory % % % all upstream changes applied / / / 3.0 (quilt) has debian/patches / / 3* / / / 2* 2* 2 / / / 1 1 1 `breakwater' branch, merging baseline / / / unmodified upstream code ---p-----p--A----p--B--C plus debian/ (but no debian/patches) / / / no ref refers to this: we --#-----#-------#-----> upstream reconstruct its identity by inspecting interchange branch Key: 1,2,3 commits touching upstream files only A,B,C commits touching debian/ only B3 mixed commit (eg made by an NMUer) # upstream releases -p- special merge, takes contents of debian/ from the / previous `breakwater' commit and rest from upstream -/- pseudomerge; contents are identical to / parent lower on diagram. % dgit-generated commit of debian/patches. `3.0 (quilt)' only; dropped by rebase tool. * Maintainer's HEAD was here while they were editing, before they said they were done, at which point their tools generated [% and] -/- commit[s] to convert to the fast-forwarding interchange branch. (Maybe the tooling is simply `dgit push'.) ! NMUer's HEAD was here when they said `dgit push'. Rebase branch launderer turns each ! into an equivalent *. Looking from the tip of the interchange view, it is I think always possible to classify these commits appropriately: pseudomerges are fairly obvious (if all three trees are identical, we descend to the parent with the most recent commit date), and the `p' special merge is the only non-pseudo merge and has a special form. So it would be possible to write a `git-debrebase' tool which would take (for example) B4, above, and be able to perform functions like: * Strip pseudomerges: Rewrite the current branch so it contains no pseudomerges, turning ...B3 into ...p-A-1-2-B3. (This should make a note, in your .git/ somewhere, of the original branch tip so that it can be overwritten with a pseudomerge.) * Cleanup branch: Reorganise the current branch so that the debian/ changes come first, turning -p-A-1-2-B3 into ...p-A-B-1-2-3. * New upstream rebase: Start rebasing onto a new upstream version, turning ...#..p-A-B-1-2-3 into (...#..p-A-B-|...#'-)p'-1-2. This would be a wrapper around git-rebase, which prepares p' and then tries to rebase 1 2 onto p'. So if you ask for an interactive rebase p' doesn't appear in your commit list. Note that the construction of p' cannot fail because p' simply copies debian/ from B and and everything else from #'. (Rebasing A and B is undesirable. We want the debian/ files to be non-rebasing so we can `git log' and get the packaging history.) * Record pseudomerge. This is like "committing" your patch queue. The LH parent is taken from the previously recorded tip. (We could perhaps check that this is consistent with what we see in debian/changelog, but that is not a sufficient check so the recorded tip check is primary.) Maybe some of these operations should automatically edit debian/changelog. The only thing that this can't easily do is permit nonlinear (ie, merging) history on the `packaging-only' branch, because upstream might contain debian/ files too, so it is not possible to distinguish a merge of two `packaging-only' branches from the special merge `p'. (Indeed I since upstream might copy debian/ from us, I think it is not easy to reliably distinguish the two parents of a `p'. In the most exciting edge case, upstream might `git merge' a previous instance of our interchange view, but I think even then everything still works.) Sean Whitton writes ("Re: Feedback on 3.0 source format problems"): > Does the [breakwater] branch contain debian/ alone? No, it also contains a complete unmodified copy of the upstream code. (Except that if upstream had a debian/ directory, it is completely replaced.) For `3.0 (quilt)' the breakwater branch contains roughly what you would get if you untarred the origs and the debian.tar.gz, and then deleted all the patches without applying them. dgit import handling -------------------- Consider a non-dgit NMU followed by a dgit NMU: interchange --/--B3!--%--/----D*--> / / % 4 / 3 / 2 / 1 2* &_ / /| \ 1 0 00 =XBC% / / --p--A breakwater / --#--------> upstream Key: =XBC% dgit tarball import of .debian.tar.gz containing Debian packaging including changes B C and patches 0 dgit tarball import of upstream tarball 00 dgit tarball import of supplementary upstream tarball &_ dgit nearly-breakwater import &' git-debrebase converted import (upstream files only) D' git-debrebase converted debian/ changes import * ** before and after HEAD Want to transform this into: I. No new upstream version (0 + 00 eq #) --/--B3!--%--/------D*-------------/--> / / / % 4 4** / 3 3 / 2 2 / 1 1 2* &_ / / /| \ / 1 0 00 =XBC% / / / / / --p--A-----B-----------------------C--D / --#-----------------------------------------> II. New upstream (0 + 00 neq #) --/--B3!--%--/------D*-------------/--> / / / % 4 4** / 3 3 / 2 2 / 1 1 2* &_ / / /| \ / 1 0 00 =XBC% / / / / / --p--A-----B--------------------p--C--D / / --#----------------------- - - / - - -----> / &' /| 0 00