Why doesn't deletion depend on it's down-context where edits do?

Create this repo

pijul init
echo -e "1\n2\n3\n4\n5\n" > a
pijul add a
pijul record --all --message base
echo -e "1\n2\na\nb\n5\n" > a
pijul record --all --message 34-ab
echo -e "1\na\nb\n5\n" > a
pijul record --all --message del-2

Unrecording (with reset) 34-ab gives no conflict. However when it’s applied again there’s a deletion conflict like so:

>>>>>>> 0 [WIY5FSJ7]
<<<<<<< 0

I’d read that as a and b were being brought back by the conflict but they’ve never been deleted - that was 3 and 4. If anything I’d have expected a conflict on unrecording 34-ab which would look like:

>>>>>>> 0 [WIY5FSJ7]
<<<<<<< 0

as the up-context of 3 was 2 but in the current state it’s been deleted.

None of that applies if instead of deleting 2 it was replaced by z as that edit does depend on it’s down-context and it’s not possible to unrecord 34-ab without also unrecording the edit 2-z.

This looks like a bug in apply. del-2 “knows” 34-ab without having it as a dependency. I’ll have a look.

Ok, there were two bugs actually, one was in unrecord, but didn’t have any visible effect: the “knows” relationship was backwards, which isn’t entirely unexpected, since the logic of every single line of unrecord is backwards (unrecord works on the EdgeMap type with fields named previous and new, and must remove the edge marked new and add one marked previous).

The other one is quite subtle, this was my previous thinking

  • easy case: when adding a vertex, if the context has been deleted by another patch, this is a conflict (a “zombie” conflict), add deleted edges around the new vertex to mark that.
  • hidden case: the patches deleting edges have a set of other patches they “know about”, which are the patches introducing vertices around the deletions. When deleting an edge, check whether the vertices around the deletion are known. If not, that’s equivalent to the previous case.

I was always a bit uncomfortable with this asymmetry, but at least the reasoning seemed rather solid. But you just found it wasn’t: it is wrong to assume that a context deletion does not know about a new vertex.



With that change, are existing repos internally correct? Or do they need to replay the patches?

Tricky question. They aren’t corrupted, but there’s an extra fake conflict.

If you solve that conflict, nothing bad will happen, you’ll just get an extra patch, and the others will be able to apply it without any consequence.

If you prefer to replay the patches, that’s up to you. Note that you might only want to do that in the case that you’ve played a similar scenario (i.e. unrecord a patch A that introduced lines that are still alive, but whose surrounding lines have been deleted by a more recent patch B, and then apply A again).

It seems like a good topic for a blog post.

1 Like