Hacker News new | past | comments | ask | show | jobs | submit login

I'm not convinced either. What's the performance of getting the the state 10 versions before? What is exactly the size difference between a git repo and a pijul repo of the same thing?

As for patch vs snapshot, that's arguing at the implementation level. It doesn't affect my use of a tool except as it relates to performance and merging/branching... etc.

Preferring a patch approach rather than a snapshot is like saying map(+)[1,1,1,1,1] != last([1,2,3,4,5]). I don't care.




You’re right about not caring about the implementation level.

But the difference isn’t just at the implementation level, it also relates to merging etc.

See here for an example of how merging works better, by taking into account intermediate commits: https://tahoe-lafs.org/~zooko/badmerge/concrete-good-semanti...

That is to say, start with version A, on one branch commit versions B1 and then B2, on another branch commit version C1. To merge the two branches (B2 and C1), Git/Subversion etc. will do a three-way merge of “A to B2” and “A to C1”. It won’t take into account B1 which provides vital information to do a better merge.


OK, but if it's needed you could derive patches from snapshots and perform the same steps with a snapshot based VC.

I may be missing something here!

PS less I seem too harsh here, I love looking into version control systems. I have worked with sccs, rcs, arch, larch, bazaar, bzr, bitkeeper, svn and of course git. Looked at darcs very briefly. Never used cvs seriously. Managed to avoid clearcase thank god.


Sure, but if you had read the manual[1], you would have learned that this is only the associativity part, which you could indeed use to provide a better merge algorithm in a snapshot-based VCS.

So:

1. You're 100% correct in saying that this can be done in a snapshot-based VCS like Git, Mercurial or SVN.

2. But you're also missing the main feature of Pijul, patch commutation, also explained in the manual. The idea is that you don't need to rebase anymore, two patches produced independently always commute, and hence patches don't need to change their identity when they are "rebased", or merged at any point in time. This has major usability benefits, such as being able to undo a "merge" (I prefer to call it a patch application) even after ten other "merges". Or choosing which part of a conflict to remove in order to solve it (if you don't choose to actually solve the conflict). With patch commutation, you don't need `git rerere` anymore, and you don't even need to branch very often, since branch are essentially an emulation of commutation (then of course Pijul still has branches, but they're quite different from Git's branches, in particular they are not as essential as in Git).

But then Pijul is still a young project, there are still a few bugs here and there. It is self-hosted, and we're quite happy using it for its own development (and the development of all companion libraries, Thrussh, Sanakirja…). But is it really ready for HackerNews-level flamewars?

[1] https://pijul.org/manual/why_pijul.html|the manual


> In Pijul, for any two patches A and B, either A and B commute, (in other words, A and B can be applied in any order), or A depends on B, or B depends on A.

This isn't exhaustive. What about the case where both patches A and B are worked on independently, and both depend on an original version of the codebase, let's call it P for parent.

A and B both diverge from P and therefore require a merge, or in git, a rebase. Over my years as a developer this scenario has caused approximately 90% of the issues with git. How does Pijul tackle it?


You can simply incorporate both patches A and B, you don't need a separate "merge" step.

If A and B have conflicts, then the resulting repo will have conflicts (but that's allowed in pijul) and you can resolve those conflicts with a third patch, C.

The nice thing is that this patch C can be used to resolve those same set of conflicts, even if someone else has a completely different history. In git, when you perform a rebase, the identity of commits is lost, and so you have to constantly re-resolve the same merge conflicts when merging between branches where one of the branches has been rebased.


That sounds great.

What about the situation where A and B don't have conflicts (as defined by the VCS), but still don't work. For example, based on a state of a piece of source code, e.g. A renames a method and all usages (works fine), and B introduces new code (but uses the original method name, also works fine). Merging them will not produce conflicts, but will not work.

In Git I always use "--exec 'mvn clean test'" when using "git rebase", to compile the source code (which would find such rename issues) and run unit tests (which would find other issues, e.g. A introduces a new mandatory column in a database table and B introduces an INSERT statement without that column).

What would be really cool is if one could say to Pijul "for any operations on this repository, execute this command to determine if the software is OK". And then forget about it. That way all operations it does it could check, and the user could never forget. I wish Git had something like that.

Or have I misunderstood something? I mean, simply relying on "no conflicts implies everything's fine" is not sufficient as far as I can see?


I would say that is somewhat outside the jurisdiction of the VCS. Sure you can have post-commit or CI hooks that ensure your code always compiles, but it doesn't need deep support from the VCS to do that.

However, the fact the pijul doesn't really treat the "no conflict" state as "special" is in some ways closer to what you want - the repo is just a collection of patches, and whether the result is "good" or "bad" is not determined by the VCS, but by whatever means you choose to employ.


I've not used Pijul, but I used Darcs — which Pijul is essentially an improved clone of — for half a decade, and I assume it's roughly the same.

The patch model is incredible. Think of "git cherry-pick". Imagine you could use that instead of "git merge" or "git rebase" for all your work. Imagine that every time you cherry-picked, it would tell you which additional commits you'd need, and then pick them for you. And that when you merged your heavily cherry-picked branch back into the mainline, it just worked. That's Pijul/Darcs.

One doesn't have to understand the "theory of patches" to use Pijul/Darcs. As a user, you just work with changes, just like Git. But the UX is much simpler than Git — in a good way.

I remember switching from Darcs to Git back in 2008 or so. It was like switching out a sleek spaceship [] for an old rusty, clanking pickup truck. Git has gotten better over the years, but ultimately, I think Github was the killer app, not Git. Going back technical merits alone, Darcs and Mercurial "should" have won that battle.

[] Albeit one that occasionally choked on its dark matter fuel for mysterious reasons. That alone contributed to a large part of the decline of Darcs. Apparently this is a solved problem in Pijul.


> Preferring a patch approach rather than a snapshot is like saying map(+)[1,1,1,1,1] != last([1,2,3,4,5]).

I assume you meant `reduce` instead of `map`.


Thanks, I knew I'd get that wrong!


> As for patch vs snapshot, that's arguing at the implementation level

??

Thats the core of any version control system, namely "what exactly am I versioning?".

For anything beyond the trivial use case (and "trivial uses" probably encompass a large majority of all usage of version control systems, so thats not to be sniffed at), this fundamental difference of "what am I versioning" impacts, well, everything.

For one thing, dealing explicitly with patches rather than snapshots means you can almost have ad-hoc branches, on the fly, AFTER the fact (ie: you only realised you wanted to separate out some commits long after you actually did them).

You can't do that with git, where every "patch" is really part of a linear series of commit where the parent of each is hardcoded into the commit blob.

Not without rewriting the history. Or revisiting the past, in the future (by writing undo commits, and branching after). Or however you want to do it.


> Thats the core of any version control system, namely "what exactly am I versioning?".

I would say that's less fundamental than answering "give me the exact state of the repo at time t"

> You can't do that with git,

Maybe I misunderstand but you can branch from some arbitrary point and cherry-pick to your heart's content. Of course the hashes won't be the same but does that matter?


> I would say that's less fundamental than answering "give me the exact state of the repo at time t"

This is indeed a very important question when you're working alone, but the notion of "at time t" changes when many people work in parallel. This is why Pijul has two notions of time:

- Patches, which always commute when produced in parallel. - The sequences of patches applied locally to a branch.

Alice and Bob working together can have the same patches and a different application order, what matters for the contents of their file is the set of patches only.

> Of course the hashes won't be the same but does that matter?

It does matter a lot sometimes, for instance if you cherry-pick, solve a conflict, and cherry pick again from the same branch, the fact that Git changes the hashes will make the conflict reappear the second time you cherry-pick.


With "patch theory" the VCS can tell you which patches depend on which patches, even if they look like a linear "tree", it helps you get the same result. Of course you can do it with git, but it helps you get there faster.

Git uses some heuristics to make things smooth, but when it fails, it fails bad. Patch theory handles those, and it cannot "fail", it simply states where the conflict is. (On patch level, not just that these files happen to conflict because these diffs conflict after a lot of rebase-rewrite.) Which will be exact, not heuristic driven and implementation dependent, like in Git.


> Preferring a patch approach rather than a snapshot is like saying map(+)[1,1,1,1,1] != last([1,2,3,4,5]). I don't care.

You don't care as long as the difference is unobservable, but sometimes it is.




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

Search: