Ideas/EssentialDependencies
In Darcs, there are two kinds of dependencies: implicit and explicit
ones. Implicit dependencies are recorded behind the scenes for every
named patch. Additional explicit dependencies can be specified using
darcs tag or darcs record --ask-deps.
Implicit dependencies are unnecessarily coarse grained if users record unrelated changes in a single named patch. As a consequence, patches that depend on such a big patch implicitly depend on unrelated changes which unnecessarily restricts possible repository manipulations.
To solve this problem, Darcs could record which implicit dependencies are essential. Essential dependencies are those implicit dependencies that Darcs would record if every primitive patch would be recorded in its own named patch.
As shown below, users can record essential dependecies by carefully recording small patches. But often users record big patches that combine many changes into a logical unit. Darcs should allow to do this without recording unnecessary dependencies.
Darcs implicitly records unnecessary dependencies
The following example motivates recording of essential dependecies by showing how Darcs unnecessarily restricts repository manipulations.
Say, we record two patches: one that creates two files and another
that adds contents to one of the files.
darcs changes -v
* added contents to essential file
hunk ./essential 1
+contents
* added files essential and unnecessary
addfile ./essential
addfile ./unnecessary
In this situation, the patch that adds contents
implicitly depends on the patch that adds the two files (because it
modifies one of them.) As a consequence, the patch that adds
contents implicitly depends on the primitive patch
addfile ./unnecessary although it is unrelated to this
change.
Say, we accidentally recorded addfile ./unnecessary
together with addfile ./essential and we want to
restructure the repository to not add the unnecessary file.
It is unnecessarily difficult to undo the primitive patch
addfile ./unnecessary: Darcs does not allow to do this
using darcs amend-record --unrecord --patch "added files"
because another patch depends on the selected patch.
Users can manually record only essential dependencies
We can use darcs unrecord followed by
darcs record to restructure the patches according to
essential dependencies.
darcs changes -v
* added contents to essential file
hunk ./essential 1
+contents
* added files essential and unnecessary [2 of 2]
addfile ./unnecessary
* added files essential and unnecessary [1 of 2]
addfile ./essential
In this situation the patch adding contents only depends
on the patch adding the essential file. Hence, we can undo
the primitive patch addfile ./unnecessary using
darcs amend-record --unrecord --patch "2 of 2".
darcs changes -v
* added files essential and unnecessary [2 of 2]
* added contents to essential file
hunk ./essential 1
+contents
* added files essential and unnecessary [1 of 2]
addfile ./essential
The selected named patch has been commuted to the top. (We could use
darcs obliterate to completely remove the now empty
patch.)
This manual procedure has two drawbacks:
Users need to calculate dependencies to partition the recorded changes into unrelated sets of changes.
The small patches no longer reflect logical grouping and cannot be pulled as a single patch.
Adding empty patches as logical units
We can bundle unrelated changes to be exchanged as a unit by recording empty patches that depend on them. Say, we want to bundle two patches, each of them adding a file to the repository.
darcs changes -v
* added files essential and unnecessary [2 of 2]
addfile ./unnecessary
* added files essential and unnecessary [1 of 2]
addfile ./essential
In this situation, we could use a darcs tag to bundle
the patches because there are no other patches in the repository. If
there are other patches, a tag is not what we want, however, because a
tag depends on the complete state of the repository rather than only on
the patches we want to bundle.
Darcs does not allow to directly record empty patches. Instead, we
first record a non-empty patch and specify additional explicit
dependencies using darcs record --ask-deps.
darcs changes -v
* added files essential and unnecessary
addfile ./bundle
* added files essential and unnecessary [2 of 2]
addfile ./unnecessary
* added files essential and unnecessary [1 of 2]
addfile ./essential
Now we can use darcs amend-record --unrecord bundle to
remove that primitive patch addfile ./bundle from the
selected patch.
darcs changes -v
* added files essential and unnecessary
* added files essential and unnecessary [2 of 2]
addfile ./unnecessary
* added files essential and unnecessary [1 of 2]
addfile ./essential
We now have an empty patch that depends on two unrelated changes so
they can be exchanged as a unit. In order to undo the primitive patch
addfile ./unnecessary we first need to unrecord the empty
patch that depends on it. Unrecording an empty patch should be easy
because other patches will never implicitly depend on an empty
patch.
We can also retroactively add new explicit dependencies to an empty
patch using darcs amend-record --ask-deps. Pulling an empty
patch with additional dependencies is possible even if a previous
version of it has been pulled previously, though the repository will end
up with both the old version and the new version. So users can use empty
patches to communicate conceptually related changes without essential
dependencies.
Darcs should automatically record only essential dependencies
It is error prone for users to record only essential dependencies. They might accidentally include unrelated changes into a patch like in the motivating example. Moreover, manually bundling unrelated named patches as logical unit is awkward because it requires a workaround to create an empty patch with explicit dependencies.
Darcs knows about implicit dependencies of unrecorded changes. For
example, when recording a new file with some contents Darcs will not aks
users to select the hunk patch adding the contents if they already
decided against including the corresponding addfile
primitive patch. darcs record --split-deps could
automatically record multiple named patches reflecting essential
dependencies, append [n of m] to the given patch name for
each of them, and then record an empty patch that depends on all of them
using the given patch name and description.
Summary,
advocating the --split-deps flag for
darcs record
To summarize, here are answers to the questions to think about when advocating a new feature.
Consequent usage of the --split-deps flag for
darcs record ensures that all implicit dependencies tracked
by Darcs are essential. End users can therefore avoid accidentally
recording unnecessary dependencies when authoring patches which lets
them (and others) later undo changes more flexibly. Automatic bundling
using an empty patch allows patch authors to communicate their changes
via a single patch that can be tracked by others. To ensure consequent
use of --split-deps, users can configure it as a default
flag for darcs record.
A typical usage scenario is the development of a large feature. It is convenient to exchange the feature using a single patch including, for example, helper functions not necessarily restricted to the feature. If others later want to use helper functions without pulling the feature, they can pull one or more of the independently recorded named patches. On the other hand, users interested in the complete implementation of the feature don’t have to select all independently recorded named patches but can instead pull the empty patch that depends on them.
This feature does not introduce any incompatibilities as users can
already achieve the effect of --split-deps with some manual
effort. Moreover, users can choose to not use the feature by not using
the flag. Existing workflows to unrecord and then rerecord changes are
simplified because all changes can be automatically structured into
minimal named patches from the start. When using
--split-deps as a default flag for
darcs record, subsequent calls to
darcs changes and similar commands showing information
about patches will show multiple named patches where they previously
showed only a single patch. The user interface of
darcs record itself would not change. A single call to
darcs record would implicitly record multiple named patches
reflecting essential dependencies. As a consequence, the
--split-deps flag has no effect on the conceptual integrity
of Darcs.
A possible unintended interaction with existing features that
manipulate patches could arise from having many small patches instead of
one big one. For example, unrecording the empty patch used to bundle
unrelated changes will not change the state of the repository. To remove
a feature, all bundled patches need to be unrecorded individually.
Presumably, this is only a minor nuisance, because
darcs changes clearly shows the individual patches and
Darcs’s features for patch selection are flexible enough to select all
bundled patches based on their names.
This proposal originated from a discussion
on patch groups. Patch groups were proposed to solve the problems of
retroactively splitting patches and grouping them into logical units.
The need for retroactively splitting patches is reduced by recording
only essential dependencies from the start. The need for a separate
concept for logical units of patches is reduced by recording empty
patches with explicit dependencies. Apart from adding the flag, no
changes to the user interface of Darcs are necessary. Therefore, this
proposal seems less intrusive to Darcs than the proposed patch groups
with all its discussed user interface changes. It also seems easier to
implement because the implementation only requires information that is
already available to darcs record.
