Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Can someone give me a real world example (person a makes X change, person b makes y change etc. etc.) that would work better in Pijul than Git?

Simplified example:

Persons A and B check out master branch.

Person A adds a.txt, commits and pushes.

Person B adds b.txt, commits and tries to push and...

1) git will not accept the push because it's not on top of current master branch, person B needs to fetch and merge/rebase before pushing again.

2) pijul will accept the change (after a pull, but no rebase) because patches A and B are independent of each other and does not matter which order they are in the history (keyword: commutation).

The value of Pijul will only start to show when you get into big three way merge scenarios. Which git users avoid like the plague because they are so nasty to deal with. Demonstrating this would need a much larger example.

edit: clarification a pull is still needed in case 2, but no rebase or merge because there isn't one for commutative patches



> 1) git will not accept the push because it's not on top of current master branch, person B needs to fetch and merge/rebase before pushing again.

But is this not the right thing to do? A kernel is a complex piece of software. Changes in one place can have very non-obvious consequences in other places (think of changes that cause deadlock because locks are applied in the wrong order). Of course, it is theoretically nice if I know that a change to e.g. documentation or fixing a typo in a comment is not affecting the Ethernet driver or the virtual file system layer, but this is down to the architecture of the project - this is not something that a version control system can prove.

Given that, it seems desirable to me that the source tree has as few different variations, permutations how to get there, and so on, as possible, since this makes testing and things like bisecting for something like a broken lock or another invariant much easier.


Thank you for answering.

For me "not needing to pull before pushing" is nice, but not game changing (but helpful to understand nonetheless).

It's more the cases that you allude to that we instinctively avoid in git!


You've never maintained a long-lived git feature branch, it seems :)

I maintain a project that is a slight modification of a very active upstream repo. The changes I maintain are rather invasive. Almost every upstream commit introduces a merge conflict with my changes.

To keep myself sane I only merge/rebase when upstream releases a new version, but it still ends up sucking up a few weeks of my time every year. During those weeks, I look enviously at pijul where the conflicts would resolve down to a handful of corrections in context at the point of divergence, instead of gigantic merge conflicts obscured by thousands of piled on patches.


You say that, but this applies to all cherry picking you can do between branches as well. As long as they don't conflict you're golden, and if there's a conflict you can commit a resolution that'll commute with your branch until you merge back into main.

It would enable so many nice and less strict workflows to actually work if it ever got momentum, I've still got hope.


The git behavior seems greatly preferable here. As mentioned in other threads, the notion of commutativity here is very weak and counterintuitive; it only seems to cover the applicability of an auto-merge heuristic, not any actual notion of correctness or semantics, so a human is needed to review the merge and re-test before anything can be known safe for pushing upstream. If anything, git is too lenient in allowing auto-merges to take place that could in principle change semantics, and it ought to enforce a manual review stage for any merge, regardless of whether the auto-merge heuristic succeeded or not.


When the contents has a conflict, git and pijul behave similarly.

When the contents are identical, but the order of commits is different, git will conflict and require manual resolution. Pijul will not.

As you say, neither will automatically check for correctness and you should run tests and CI when merging.

Pijul just removes the manual work when there is no conflict in the contents but the history is different.


> When the contents are identical, but the order of commits is different, git will conflict and require manual resolution.

But why would this normally happen? Different developers working on the same files which by chance make the same changes? Isn't that unlikely?


> When the contents has a conflict, git and pijul behave similarly.

Not really: Pijul can record a conflict resolution as a patch, and apply it in a different context. Also, the conflict doesn't "come back", so you don't need extra hacks like rerere/jujutsu.

> Pijul just removes the manual work when there is no conflict in the contents but the history is different.

This is true, but could be confusing as our definition of conflicts isn't based on contents, but on operations, which is very different from Git (Git doesn't detect all conflicts).


> the notion of commutativity here is very weak and counterintuitive; it only seems to cover the applicability of an auto-merge heuristic

This is completely false: in Pijul, any patches that could have been produced independently can be applied in any order without changing the result. There are 0 heuristics in Pijul, unlike in Git where even random line reshuffling can happen (there are examples in the "Why Pijul" section of the Pijul manual).

Obviously, deciding whether a merge has the correct semantic is Turing-complete, and Pijul doesn't try to do any of that.


Merges are bad only when all parties involved edited the same code. There's no programmatic way to solve this problem. It's an administrative problem: someone has to decide whose code is the right one to use.

If changes coming from both sources are independent, then rebase in Git is trivial as well, and there's nothing to be afraid of.


> It's an administrative problem: someone has to decide whose code is the right one to use.

Or maybe an architectural one.


Does that only apply to adding new files? The changes in commit A could affect the behavior of the changes in commit B even if they are different files.


No, it applies to everything. If adding patches A and B (same or different files) will lead to same result regardless of which order they are applied, they are called "commutative" and pijul won't care which order they are in your history.

It only tracks content of files, not semantic or behavior changes.


git can already do this as long as there isn't a conflict. Maybe pijul has better three way conflict resolution, but those can be risky, and avoiding those rare situations wouldn't offset the vast amount of tooling that got has.


Git would make you merge or rebase, but yes there wouldn't be a conflict. They're saying Pijul would let you directly push without having to deal with the diverging histories.


Which tbh is a bad thing. Just because change a doesn't textually touch change b doesn't mean they don't interact.

Unless your VCS is handling CI for integrating changes on push, you really need to pull down the upstream changes first and test them combined with your code before blindly pushing.


> Which tbh is a bad thing. Just because change a doesn't textually touch change b doesn't mean they don't interact.

A good example for this is code which grabs several locks and different functions have to do that in the same order, or a deadlock will result. A lot of interaction, even if changes might happen in completely different lines.

And I think that's generally true for complex software. Of course it is great if the compiler can prove that there are no data race conditions, but there will always be abstract invariants which have to be met by the changed code. In very complex code, it is essential to be able to do bisecting, and I think that works only if you have a defined linear order of changes in your artefact. Looking at the graphs of changes can only help to understand why some breakage happened, it cannot prevent it.


I have clarified the comment above. A pull is needed before pushing. That pull does not need a merge or a rebase like git does because the order of commits A nd B does not matter (iff they are commutative). This gets a lot more useful when there are more than two patches to consider.


That seems like a very important point; how does pijul deal with such "effects at a distance"?


By not being a CI tool, nor claiming to solve such Turing-complete problems.

Pijul has a theory of textual changes, but indeed doesn't care at all about what you write in your files: that's your problem!


pijul has a lot of theory and engineering to figure them out, dealing with them better than git is one of the major reasons it exists at all, and darcs before it.


> darcs before it.

Darcs is older than git.


True.

In my defense, 3-way merges are older :)


You kinda missed the point.

You have two repos with different history:

master -> patch a -> patch b

master -> patch b -> patch a

But the contents of the files are equal after applying both patches (in either order).

Git will consider these to be two different, Pijul thinks they're the same.

This is a simplified example. It only gets interesting when there are a lot of patches, some of which are commutative and some are not.


What benefit is there to the VCS knowing that these histories are equal? That's valuable in verification or efficient binary patching, but I don't see how it matters in version control. When would I want to compare two repositories that were patched in different orders?


I'm guessing that it makes it easier to pick and choose between a bunch of patches. This is something I sometimes want to do in Git, but doing so requires a bit of planning. Have all the independent features branch from the same point, then, to 'assemble' them, do an octopus merge.

If the VCS knows about dependencies between patches intuitively, it could free me from having to explain it, which in the case of Git, requires following procedures that I'm unlikely to convince any of my coworkers to follow ("ohay, first, decide on the earliest point in the history from which this patch could make sense, rebase onto that....")


Imagine you are working on a patch heavy project. Like the Linux kernel. Where there are a lot of patchsets going around that are not in the mainline.

You and I, who are both working off of main, and who have both separate merged in a few patchsets that are relevant to our shared module of interest. We can merge and compare our branches, and the differences in terms of nursing patches without having to be rigorous about reconciling or histories.


This is not really compelling. Pulling and rebasing before a push is standard workflow and lets you test with the new changes before pushing.


That may be standard in some shops, but definitely not all.

I view anything that interferes with a push as a threat to the VCS, since it encourages developers to keep changes local and unavailable to their teammates. The only exception would be direct pushes to main.


That doesn't interfere with a push, you're just expecting to blindly push without considering the state of the repo.


> git will not accept the push because it's not on top of current master branch, person B needs to fetch and merge/rebase before pushing again.

Hmm...that seems like a feature to me, not a bug.

To me nothing of substance should happen in the repository, it should all happen in the local working directory.

¯\_(ツ)_/¯


> To me nothing of substance should happen in the repository,

The idea is that with pijul nothing of substance would happen on the server in this example, it is the same process that would happen if you were doing it all locally.


Hmm...so if something did need to happen, pijul would also reject and I would have to pull, do the local edits until everything is consistent and then push, just like git.

So it's a low-impact optimization of the fast path?

But actually, how does pijul know there are no conflicts? Textually?

https://pijul.org/manual/conflicts.html

Hmmm...yeah looks like it's purely textual. Er, no. There can be semantic conflicts that I need to resolve that do not conflict textually. The test suite needs to be green locally on my machine, and then we replace the Top of Tree wholesale with the code that passed the tests locally on my machine.

So to me this feature of pijul is clearly an anti-feature, a bug, and the git behavior is correct.


> Hmm...so if something did need to happen, pijul would also reject and I would have to pull, do the local edits until everything is consistent and then push, just like git.

Unlike git, pijul has first class conflicts, pijul unlike git does not reject in this example.

My knowledge is limited, but from my testing that means the conflict exists in the history, at least if your merge style allows for that(similar to how in git you can choose to always rebase or use merge commits).

The conflict is resolved with a new patch.

I did not spot much in the documentation with a quick search but on the man page there is a small blurb on first class conflicts

> First-class conflicts In Pijul, conflicts are not modelled as a "failure to merge", but rather as the standard case. Specifically, conflicts happen between two changes, and are solved by one change. The resolution change solves the conflict between the same two changes, no matter if other changes have been made concurrently. Once solved, conflicts never come back.

- from https://pijul.org/


You’re describing CI, not git nor pijul, nor any other version control system.


Was going to say exactly this, though I do wonder if it's just me being too set in my thinking around how I think version control should work.


I believe that even git would work in this scenario because a.txt and b.txt are separate and independent thus a rebase in git is not required. The point at which this becomes an issue is when both person A and B try to make changes to the same file and specifically the same blob of text within that file. I could be wrong but this should be simple enough to prove out because I've run into this situation before where I forgot to rebase before pushing my changes but git still accepted the changes as they were independent of the changes that person B made.


git wouldn't accept a push with conflicting changes on the remote but that's just because pushes are dumb (not bad, they just don't do anything fancy).

The solution would be to pull upstream changes (so you know what you are potentially pushing your changes into) and then push.


> thus a rebase in git is not required.

A rebase is never required in Git. (people/maintainers may disagre) but a merge will always do.

Having said that. In your scenario provided, a pull + merge/rebase will be required. It will then resolve automatically, and without conflicts. But a human has to be involved to provide a strict sequence/dag of the those commits.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: