=head1 NAME git-debrebase - git data model for Debian packaging =head1 INTRODUCTION git-debrebase is a tool for representing in git, and manpulating, Debian packages based on upstream source code. The Debian packaging has a fast forwarding history. The changes to upstream files are represented as a series of individual git commits, which can worked on with rebase, and also shared. git-debrebase is designed to work well with dgit. git-debrebase can also be used in workflows without source packages, for example to work on Debian-format packages outside Debian. git-debrebase is not very suitable for use by Debian derivatives, to work on packages inherited from Debian, because it assumes that you want to throw away any packaging provided by your upstream. =head1 DIAGRAM ------/--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 ---@-----@--A----@--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 -@- anchor 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 *. =head1 BRANCHES AND BRANCH STATES git-debrebase has one primary branch, the B. This branch is found on Debian contributor's workstations (typically, a maintainer would call it B), in the Debian dgit git server as the suite branch (B) and on other git servers which support Debian owrk (eg B on salsa). The interchange branch is fast-forwarding (by virtue of pseudomerges, where necessary). It is possible to have multiple different interchange branches for the same package, stored as different local and remote git branches. However, divergence should be avoided where possible - see L. A suitable interchange branch can be used directly with dgit. In this case each dgit archive suite branch is a separate interchange branch. Within the ancenstry of the interchange branch, there is another importnt, implicit branch, the B. The breakwater contains unmodified upstream source, but with Debian's packaging superimposed (replacing any C directory that may be in upstream). The breakwater does not contain any representation of Debian's changes to upstream files. The breakwater starts at an B, which is usually a special merge generated by git-debrebase. When working, locally, the user's branch can be in a rebasing state, known as B. When a branch is unstitched, its previous tip is recorded so that it can later be stitched into the fast-forwarding interchange form. An unstitched branch may be in B state, which means it has a more particular special form convenient for manipulating the changes to upstream files. =head1 BRANCH CONTENTS It is most convenient to describe the B state first. It contains B (ancestors first): =over =item Anchor An B commit, which is usually a special two-parent merge: The first parent is a previous breakwater branch, whose upstream files are irrelevant, and whose packaging files are identical to the anchor's. The second parent is an upstream source commit; whose packaging files (if any) are irrelevant, and whose upstream files are identical to the anchor's. Anchor merges always contain C<[git-debrebase anchor: ...]> as a line in the commit message. Alternatively, an anchor may be a single-parent commit which introduces the C directory and makes no other changes: ie, the start of Debian packaging. =item Packaging Zero or more single-parent commits containing only packaging changes. (And no changes to B.) =item Delta from upstream Zero or more single-parent commits contaioning only changes to upstream files. =back The B (unlaundered) branch state is the same, except that it may contain, additionally, in B: =over =item Linear commits to the source Further commit(s) containing changes to to upstream files and/or to packaging, possibly mixed within a single commit. (But no changes to B.) =item Patch addition for `3.0 (quilt)' Commit(s) which add patches to B, and add those patches to the end of B. These are only necessary or useful when working with packages in C<.dsc 3.0 (quilt)> format. =back The B branch state is the same, but may additionally contain (in some order, possibly intermixed with the extra commits which may be found on an unstitched unlaundered branch): =over =item Pseudomerge to make fast forward A pseudomerge making the branch fast forward from previous history. The contributing parent is itself in interchange format. Normally the overwritten parent is a previous tip of the interchange branch, but this is not necessary as the overwritten parent is not examined. =item dgit dsc import Debian .dsc source package import(s) made by dgit. Each such import must be a two-parent pseudomerge whose contributing parent is in the special dgit format (not described further here). The overwritten parent must be the previous interchange tip (and will be generated that way by normal use of dgit). =back =head1 STITCHING, PSEUDO-MERGES, FFQ RECORD Whenever the branch C is unstitched, the previous tip is recorded in the git ref C. Unstiched branches are not fast forward from the published interchange branches. [1] So before a branch can be pushed, the right pseudomerge must be reestablished. This is the stitch operation, which consumes the ffq-prev ref. When the user has an unstituched branch, they may rewrite it freely, from the breakwater tip onwards. Such a git rebase is the default operation for git-debrebase. Rebases should not go back before the breakwater tip, and certainly not before the most recent anchor. Unstitched branches must not be pushed to interchange branch refs (by the use of C or equivalent). It is OK to share an unstitched branch in similar circumstances and with similar warnings to sharing any other rebasing git branch. [1] Strictly, for a package which has never had Debian changes to upstream files, the interchange and breakwater branches may be identical, in which case the unstitched branch is fast forward from the interchange branch and no pseudomerge is needed. =head1 OTHER MERGES Note that the representation described here does not permit general merges on any of the relevant branches. For this reason the tools will try to help the user avoid divergence of the interchange branch. Automatic resolution of divergent interchange branches (or laundering of merges on the interchange branch) is thought to be possible, but there is no tooling for this yet: Nonlinear (merging) history in the interchange branch is awkward because it (obviously) does not preserve the linearity of the delta queue. Easy merging of divergent delta queues is a research problem. Nonlinear (merging) history in the breakwater branch is in principle tolerable, but each of the parents would have to be, in turn, a breakwater, and difficult qeustions arise if they don't have the same anchor. We use the commit message annotation to distinguish the special anchor merges from other general merges, so we can at least detect unsupported merges. =head1 TERMINOLOGY =over =item Pseudomerge A merge which does not actually merge the trees; instead, it takes its tree by construction from one parent. These are used to make a rewritten history fast forward from a previous tip, so that it can be pushed and pulled normally. Manual construction of pseudomerges can be done with C but is not normally needed when using git-debrebase. =item Packaging files Files in the source tree within B. (Does not include anything which may exist in B.) =item Upstream The version of the package without Debian's packaging. Typically provided by the actual upstream project, and often tracked by Debian contributors in a branch C. =item Upstream files Files in the source tree outside B. These may include unmodified source from upstream, but also files which have been modified or created for Debian. =back =head1 APPENDIX - 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% / / --@--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 We 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% / / / / / --@--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% / / / / / --@--A-----B--------------------@--C--D / / --#----------------------- - - / - - -----> / &' /| 0 00 =head1 SEE ALSO dgit(1), dgit(7), dgit-maint-*(7)