Working "without" channels

Continuing the discussion from Phenomenological Pijul (or Pijul from the outside):

The OP had two questions:

  1. How to work on multiple features/bugs at the same time without using (named) channels?
  2. How does this integrate into a continuous integration system?

As mention in the other thread, a channel is the means from which to create a working tree through the use of a concept called state. So, whenever you need to manifest your wisdom into a working tree, you employ a channel. (Maybe, technically, there are other ways, but this is the intended interface.)

Q 2. How does not using channels integrate into CI?

It doesn’t. When you want to kick off the CI runner, you would create a special channel (that the CI can pick up on) and push all relevant changes to that channel. All dependent changes get pushed as well, resulting in a final state. The CI runner manifests this state into a working tree and works on that data.

This is how the Nest works. Each discussion represents a special channel named “<colon><discussion-number>”, e.g., :756 for discussion 756, which you can push/pull changes to/from. A CI would pick up on these channels and test the state that results from merging a particular base channel (usually main) and the patches in the discussion.

Q 1. How to work on multiple features without using multiple channels?

By above supposition, always use at least one channel. Thus, the question is about not using multiple channels.

Small recap about the meaning of channels, because it’s important to fully understand them. Channels contain changes in a particular order (the log order). Any collection of changes form a particular state. The order is technically not important (because the application of independent changes is commutative) but may be of high importance from a user’s perspective to “go back in time”. The log order fully determines to which states a user can immediately go back to. E.g.:

Change TWPJXHAFKIGDWPYUW2DUJZZEMRG743BHJ3MIMHD6QFRT4NQG42LAC
Author: spacefrogg
Date: 2023-05-09 10:23:34.463488474 UTC
State: MKROSKG5H45YIRSOJBWNSVEBBHMP3EHVY2SBGEISBKY7NJZP2MIAC

    added a

Change 2AEC5EQWNDITJLMEBP7BGLD5EMA7KSC5K7OHNRLQNNKXWE4DAF7QC
Author: 
Date: 2023-05-09 10:23:37.240641887 UTC
State: 3R7WEC7HIOGPOJMQYSVJNQAPAX5NXK6TEURJYWDKR2ZL6EFQGOLAC

As you can see, you can reach two states in this log-ordered channel, MKR and 3R7. Would these two changes be independent, you could not immediately reach the state that only contained the change TWP but not 2AE. The reason is purely the log order.

The current state of the channel is always the state at top-most change in the log (here, MKR) and will be the same for all log orderings of changes. This means when you and a collaborator have pulled-in the same changes in different order, your logs will look differently and intermediate states will be different, as well, but the current state at the top-most change will be the same again. See Move through history for details.

Now, because the application of independent changes commutes, pijul opens up new ways of modifying your repository state. While in git et al. repository state is a linearized set of commits, in pijul it remains a graph with multiple endpoints, called the independent changes. Like in git, in pijul, changes know about their dependencies. So, when in git you need to know a single commit hash to identify the complete repository state (because you can implicitly trace back the dependency chain up to the root commit), in pijul you need to know all independent changes and can retrace all other changes from there. Technically this means, the minimum set of changes that identifies a particular state is the set of independent changes (not all changes).

Finally, to the initial question. Working with multiple features means working with these independent changes. Right now, pijul does not have any supporting tooling for this except one. When you know that a particular feature is identified by the independent change ABCD, it is enough to push ABCD to another repository and pijul will make sure to also push all necessary dependent changes as well.
Currently, it does not help you cutting out a sub-graph of changes that only influence a single independent change (or a named set of them). You have to shave of that sub-graph one change at a time or name all the right changes at once.
Also, there is currently no user-facing tooling to help you visualize the influence of a change downstream. You would need this to efficiently identify the independent changes that form a “feature” looking from an intermediate change.
There is currently no tooling to identify independent changes in the log or to list only the independent changes. This might be interesting to identify the “features” that currently occur in your repository.

So, right now, you are left to the following approach. As long as two features (or bugs) touch separate files, you are good to go. You can look up the log of changes touching particular files and thus recreate the list of changes that make up a feature/bug. For pushing, you only need to know the last change. For cutting them out of your tree, you would need to generate the list with pijul log --hash-only -- <file>. And unrecord this list of changes. This might still fail when a changes touches more than your intended set of files, thus creating interdependencies to other changes. But this is an inherent feature of version control. Unrecorded changes are not lost but you would want to keep them in some other channel or repository for easier retrieval.

When it comes to the claim that “channels are not branches” or “channels are not so often needed”, it means the following. Suppose a collaborator has written a feature you want to try out. In pijul you can just pull in the feature into your current channel and throw it away later using above approach. It does not involve creating a new channel just for trying out somebodies feature.

Thank you very much for the detailed response. That makes sense.

So, I would guess that, given the current state of the tooling, it’s pretty easy to use one channel as a “work” channel for multiple tasks, but only for small-ish tasks with a low number of changes. Based on what you’ve said, if I knew a task was going to take weeks and lots of changes, I would still probably create a named channel for it.

Since I couldn’t find user-level per-channel permissions in the nest (they could be there, I just haven’t found them), I couldn’t wrap my head around the idea of using main as a local WIP channel that never gets pushed.

Here is the difference that makes communicating features/fixes between collaborators in git so natural and (in my opinion) misses a lot of tooling in pijul to do the same: In git, if you want to communicate a fix to a collaborator, you’d make some commit into a branch or put a tag on it and say: “Here, take this branch/tag and test my fix!” Only if you would want to integrate said fix into “main” you would cherry-pick or merge “main” and the other branch/tag. This second step would involve looking at specific commits and making choices.

In pijul, though, a single fix/feature can consist of any number of independent changes (at least one). What pijul supports, is, you can record an arbitrary change that has all relevant independent changes as dependencies and communicating just this one last change to a collaborator. After pulling this change, it can be dropped again to “unbind” the independent changes again. What pijul is missing, though, is to label/tag single changes or arbitrary groups of changes. The only thing you can do right now is either communicating the change id of the “collector change” or push it into a new channel and communicate that.

So, you cannot easily manage sets of independent changes mostly, because you cannot visualize and tag them for yourself or somebody else.

I modified the shell script that is in the pijul folder to generate a HTML file to visualize the dependency graph. See Dependency graph

This is a bit confusing because something independent has no dependencies, but it could have dependents. So, can you say that the change of a line in a file is dependent on the change that created the file, and the only root changes are those that create files?

You are right! I should have named them “head changes” instead. What I wanted to describe are the changes that no other changes depend on.