Some thoughts about recording differences

Wed, 21 May 2008 17:13:01 +0200
philosophy

When recording changes in some software there are basically three approaches, with their different advantages and disadvantages.

One approach is just record modifications chronologically. Each modification is just a little diff (or some glorified variant of diff, or if you insist something that is no diff but just has some similarity). Advantages are:

It keeps itself out of the way. You just do modifications and store them somehow one after the other.

You can reconstruct all past points, so can regain missing documentation by looking at the evolution in time.

So it is no surprise that essential every tool (i.e. all the VCSes) to handle non-packaging work on software essentially uses this way. If you have an canonical other source for the software (like an upstream for an package), it has quite some severe drawbacks:

Reviewablity does not scale. While every single diff can easily be reviewed, the mass is not. Most changes are relative to past versions of the software. If something introduces a problem or and upstream change introduces a problem with that, the fix might only show up years later, separated by tons of other changes in between. (The effect especially with changing upstream always depends a bit on the later merging, but the worst case is still the same).

For the same reason changes cannot be easily extracted. Single commits usually are fine, but what of those past changes is needed to make some specific change in the functionality is easily lost after some time, some improvements and updates to new upstream versions. The whole approach degenerates to having a single large .diff.gz file of the package. (Except one has a bit of history recorded, so when sorting out the stuff in that diff one can better guess what effect a single unattributable line has).

The next possibility is to store modifications sorted by topic and against upstream (either as .diff files relative to the upstream source, as topic branches, or or or). Advantages:

As you have to send the patch upstream anyway, you have to create such an patch initially, anyway. Also each is in a format that if upstreams wants to apply a single one, each is in the correct format for this.

Branches relative to a (relatively) fix point are usually use to store in VCSes.

When other people want to pick a subset of those patches, they only have to do the merging, and not dismerging with the missing ones first.

On the other hand, there are some disadvantages with this:

As the differences are relative to the upstream code, multiple patches are in general not applicable without additional merging.

Because of this, those patches cannot be used to generate the source to build the Debian package.

Thus those patches by itself are never directly used, unless the maintainer regularly tests them, they are essentially untested and will see bitrot.

As those are not the changes to the package because of the missing merge, they are nice for a cursory review, but if you want the review the actual changes, you need to review the merged variants.

Last but not least, there are stacked patches, i.e. patches that are supposed to be applied in a specific sequence. Advantages:

The patches itself are actually used. Thus they get wide testing and bitrot cannot happen that easily.

Equally, reviewing the actual changes can be separated into the different patches, as connected changes are next to each other and the files describe the changes without pitfalls in merges.

If someone else wants to use multiple patches from the start of the sequence, no merging is necessary. They can directly be applied.

Given these advantages, it is no big surprise that all Debian specific patch management tools (like dbs) and other programs to deal deal with multiple patches against other people's code (like quilt) use this approach. Though there are also some disadvantages:

Ordering patches is not important. Only unrelated patches can be skipped to have later patches applied cleanly, so ordering needs to predict what patches are more likely to be used by other people.

Testing only happens for the whole stack. If some match modifies parts that a later patch removes, bitrot can still happen.

Extracting those patches from the currently available VCSes is not trivial.

So the format most suitable to Debian packages (stacked patches) is the total opposite of a format most suitable when you are upstream yourself and nothing is suitable for everything. There are many different thinkable ways to combine the different things to get more of the advantages, though many are a bit lacking (like storing quilt series in a VCS as text files), not yet possible or non-trivial with the current tools. Hopefully the future will improve that.