Modify change that has dependencies

Hi!

I found the approach of Pijul interesting, and I started experimenting with it. Sorry if my question is not very wise, but how is it possible to rewrite some change in history that has dependent changes?

My experimental use case is:

I have a bunch of projects, most of them have a shared codebase. I want to organize them as a monorepo with different channels to avoid repeating myself.

I have the following imagine history:

A -> B -> C -> D (main)
       -> E -> F (channel)

I want to change B change (e.g., fix a minor bug or change dependency versions in Cargo.yaml, etc.), but I want to keep all other changes (C, D, E, F).

Is it possible to achieve this with Pijul? If yes, how can it be done?

Thanks in advice :slight_smile:

Hi! Welcome here.

This isn’t yet possible, but I’ve been working on things like this recently, I would hope this will finally come before the end of this year.

Some things that “sound easy” for other version control systems, like rewriting history, are sometimes much much harder to implement in Pijul than in others. Some things are also many times easier, like commutative patches.

Nice to hear that! Thanks for the reply

Just curious: why would you want to change B, instead of creating a change G and adding it to both channels? That would seem more logical to me. The notion of history is less important in pijul than in git, the way I see it.

One simple example I can think of: You accidentally check in a secret key and don’t notice for a while. Once you realise, you want to remove it from the history.

Sometimes errors like that happen and it’s often insufficient to remove it in a patch. You want to scrub all trace of it from the history without having to unrecorded and attempt to rerecord every dependent change.

1 Like

I thought I could do pijul fork --state B rewrite , then modify on rewrite that change I want, and then re-apply rest of the patches.

But right after fork shows diff of file was deleted and re-created. Minimal example:

pijul init && pijul add .ignore && pijul record --all -m import
state=$(pijul log --state --limit 1 --output-format json | jq -r '.[].state')
echo .mypy_cache >> .ignore
echo Hi > x.txt
pijul add x.txt && pijul record --all -m next
pijul diff  # notice empty output
pijul fork --state "$state" rewrite
pijul diff  # notice x.txt shown both as "File deletion" and "File addition" - weird

Attempt to continue didn’t work either

next_hash=$(pijul log --limit 1 --output-format json | jq -r '.[].hash')
pijul channel switch --force rewrite  # drop that weird diff and switch anyway
pijul record --amend --all -m init  # fix message from "import" to "init"
echo target >> .ignore  # just to make application harder
pijul record --all --amend
pijul apply $next_hash
pijul log # shows that old "import" change was brought in additionally to amended
pijul diff # shows deletion of both x.txt and .ignore for some reason but both are in workspace unaffected

Only after pijul reset --force I see expected state. E.g. additional version of .ignore that I assume and indication of conflict I was expecting (also visible as move).

From this experiment I understand that Pijul:

  • Can only amend/unrecord tip records
  • My assumption that I can cherry-pick records and insert records in between “unrelated” evolutions was wrong. We always apply whole sub-graph with all dependencies and no way to remove (“rebase”) dependency.
  • Seems like resolving conflicts happens on top rather than on bottom of conflicting changes.

P.S. I’m new to Pijul. Expect nonsense.