Pijul

How to combine patches?

I’m trying to write a long tutorial based on patches, showing & explaining to readers a series of changes to make to an initial hello world into a finished product. I thought pijul sounded perfect for this, plus, I’ve long been interested in pijul anyway.

While Git would allow me to encode my patches into ascii (can pijul do this?), pijul would allow me to fix errors made in the beginning of the tutorial then reorder the patches.

However, I can’t figure out how to combine patches in history.

Original: A -> B -> C -> D
With fix: A -> B -> C -> D -> B_fix
Reordered: A -> B -> B_fix -> C -> D
Merged B patches: A -> B' -> C -> D

How would I do that last step? Is it possible?
If not, is there a way to ascii-encode the net result of multiple patches?

Hi! Welcome here.

Not yet. Pijul patches store more information than what Git diff would give you. In particular, Pijul knows about conflicts. Being able to show patches as ascii, even if it implies a small blowup in the size of the representation compared to binary, would be a really fundamental feature Pijul is still missing.

It depends. In Pijul, patches producible independently commute, so there’s no need to explicitly reorder them (unlike in Darcs for example). The good news here is, if C and D could have been made independently from B and B_fix, you can unrecord B and B_fix, and record B', without changing C and D. However, if C or D (or both) depend on B, then you’ll have to change them too, and we don’t have a good way to do that yet.

I hope to be able to write a command for this soon enough.

1 Like

It depends. In Pijul, patches producible independently commute, so there’s no need to explicitly reorder them (unlike in Darcs for example)

Got it. Now that I think of it, a way to represent (in ascii) the net of multiple patches would do exactly what I’m looking for.

Being able to show patches as ascii, even if it implies a small blowup in the size of the representation compared to binary, would be a really fundamental feature Pijul is still missing.

And I’d love to make a contribution to pijul, however small it may be. I was hoping to contribute to the nest’s frontend, but it seems to be closed-source (it there a thread discussing why?).

If I wanted to take a shot at creating a way to ascii-encode patches, it sounds like I’d just need a way to convert an instance of the Patch enum to/from a pretty string? In that case, may I ask what PrettyPatch does?

Thanks!

PrettyPatch was a first try at this, but it was never finished. Contributing to Pijul at the moment is tricky, as I’m in the process of rewriting the foundations (libpijul), now that I understand the full story. The patch format will change once again, although not conceptually (I’m just making it smaller on disk).

But if you want to take a shot at this, you will have my full support (ask anything), and I’ll integrate your changes in the next version.

Also, after I’m done with this, open-sourcing the Nest will be my next project.

Awesome!

I was able to make a one-line fix (in read_key) to PrettyPatch to allow it to correctly translate back into an UnsignedPatch.

My current (ugly) “pretty printing” of PrettyPatch is as follows:

PrettyPatch { header: PatchHeader { authors: ["Florent Becker <florent.becker@ens-lyon.org>"], name: "Fixes in the test suite", description: None, timestamp: 2018-04-08T14:59:53.077354432Z, flag: (empty) }, dependencies: ["69FSXS1UWZwqQ5AdmiBQeBtYK2B6UtZALQfnzsVdRaMCaQEpEaiqoBwBao6PeL2GphzwTCxYEiz71h7rg75L3w6P"], changes: [NewEdges { previous: 8, flag: 24, edges: [PrettyNewEdge { from: "1.MF1Bc9zzEzB", to: "1.M5JWbMBVdif", introduced_by: 1 }], inode: "1.foh4EGyS55" }, NewNodes { up_context: ["1.M5JWbMBVdif"], down_context: ["1.MQhrcxpUrFh"], flag: 0, line_num: 3, nodes: [String("    REMOTE_PIJUL=\"$PIJUL_EXE\" pijul key upload $USER@localhost\n")], inode: "1.foh4EGyS55" }, NewEdges { previous: 8, flag: 24, edges: [PrettyNewEdge { from: "1.GjNc5KjH9zP", to: "1.GZfw4WunYis", introduced_by: 1 }], inode: "1.LQM2cdzDY3" }, NewNodes { up_context: ["1.GZfw4WunYis"], down_context: ["1.Gu5H68YmmFu"], flag: 0, line_num: 4, nodes: [String("  export PIJUL_SRC_DIR=\"$BATS_TEST_DIRNAME/../..\"\n")], inode: "1.LQM2cdzDY3" }, NewEdges { previous: 8, flag: 24, edges: [PrettyNewEdge { from: "1.HEUd7kBkynw", to: "1.H4mx6wNGNXR", introduced_by: 1 }], inode: "1.LQM2cdzDY3" }, NewNodes { up_context: ["1.H4mx6wNGNXR"], down_context: ["1.HQBJ8Z1Fb4T"], flag: 0, line_num: 5, nodes: [String("    export PIJUL_EXE=\"$PIJUL_SRC_DIR/../target/debug/pijul\"\n")], inode: "1.LQM2cdzDY3" }] }

Turns into:

PIJUL PATCH 2018-04-08 14:59:53.077354432 UTC
Florent Becker <florent.becker@ens-lyon.org>
Fixes in the test suite
69FSXS1UWZwqQ5AdmiBQeBtYK2B6UtZALQfnzsVdRaMCaQEpEaiqoBwBao6PeL2GphzwTCxYEiz71h7rg75L3w6P
EDGES 8 24
1.foh4EGyS55
1: 1.MF1Bc9zzEzB -> 1.M5JWbMBVdif
NODES 3
0 1.foh4EGyS55 1.M5JWbMBVdif 1.MQhrcxpUrFh
+     REMOTE_PIJUL="$PIJUL_EXE" pijul key upload $USER@localhost

EDGES 8 24
1.LQM2cdzDY3
1: 1.GjNc5KjH9zP -> 1.GZfw4WunYis
NODES 4
0 1.LQM2cdzDY3 1.GZfw4WunYis 1.Gu5H68YmmFu
+   export PIJUL_SRC_DIR="$BATS_TEST_DIRNAME/../.."

EDGES 8 24
1.LQM2cdzDY3
1: 1.HEUd7kBkynw -> 1.H4mx6wNGNXR
NODES 5
0 1.LQM2cdzDY3 1.H4mx6wNGNXR 1.HQBJ8Z1Fb4T
+     export PIJUL_EXE="$PIJUL_SRC_DIR/../target/debug/pijul"

I think I’ll have to read more about how Pijul works in order to devise a more logical encoding (I’m open to suggestions!). I also think some fields are redundant, such as flags seemingly the same for all nodes and up/down contexts seemingly always being arrays of length one.

1 Like

Cool! The only thing that remains to do is print the contents of the edge targets in case of deletions. It’s useless for the algorithm but interesting to humans.

Deletions are just edges with edge.flag == EdgeFlags::DELETED.
For conflict resolutions (which are often edges too) the display will be harder.

I think, it would be nice to be able to simply merge some patches, or even do an amend, like in git or mercurial. Especially when you have local changes in your project, which you don’t want to change, it’s a bit complicated now.
After unrecording the patches you either have to select each change again, or you make some temporary record containing the local changes befor you unrecord, so you can just record all, and then unrecord the local changes again.

Will do! I’ll also add context to the line additions.