7 ms·
How does this compare to git?
by gozzoo 10y ago
How does this compare to git?
- lvh 10y agoGit (and mercurial, and a few others) are snapshot-based. That means that they think of the world as states, with changes between them. Darcs, and pijul, are patch-based. That means that they think of the world as an ordering of patches. Patches aren't the same as commits: commit orderings, for example, are fixed, whereas patch orderings are computed. They can change when you e..g merge a "branch". Branching is similarly "simpler": a branch is just a collection of patches, not just a single commit with an implicit DAG attached to it.
- jdbernard 10y agoGit stores diffs, not snapshots. A commit is a changeset, literally a patch that you can export with `git diff`. Ordering of is layered on top of that and informs things like merges. Can you explain a little more what you mean?
- qznc 10y agoGit does store snapshots, not diffs. Look into the files in .git/objects/* ;)
- deleted 10y ago[deleted]
- tghw 10y agoNot sure why you're getting downvoted, you're describing git correctly. If anyone is questioning this, just play with `git rebase -i [some old changeset id]` and you'll see that it's just an ordering of patches.
- lvh 10y agogit rebase -i does not demonstrate that gits internal model involves a DAG of snapshots (objects); it only demonstrates that git is sometimes willing to move the contents of one of those snapshots around to create a new snapshot. That is very different from a patches-always model, as I have illustrated in a sibling comment with an example link.
- mst 10y agorebase turns the snapshots temporarily into a stack of patches, lets you play with them, then turns them back into snapshots. In fact, this is why rebase is an out-of-band tool that has odd effects on shared history - specifically because it's inverting git's model into something more like pijul's, and therefore isn't really native-to-git.
- lvh 10y agoInternally, git objects are snapshots -- the differences are computed on demand. That is a critical difference, because it has implications for how merging can work. For example: https://tahoe-lafs.org/~zooko/badmerge/simple.html https://tahoe-lafs.org/~zooko/badmerge/simple.html Even when using git am or send-email or whatever, yes, you're sending a patch -- but the way to apply that patch is to turn it into a commit and then cherry pick or rebase or merge or manually fix conflicts or whatever. In darcs and pijul, the model is _always_ that set of patches.
- jdbernard 10y agoSo, I didn't believe you because my internal mental model of a git repo is a DAG of changesets. And indeed, that is a good way to think about it, because almost all of git's operations behave like this. Commit history is almost always presented to the user as a series of diffs. But, you are correct. Internally, git stores the full contents of files and computes the diffs on the fly. For others' benefit, if you want to test for yourself, create a new repo, add a file and make a series of commits with changes. Git objects are compressed with DEFLATE (zlib) so gunzip and unzip won't work. I used https://github.com/jezell/zlibber https://github.com/jezell/zlibber because I was too lazy to write my own quick zlib wrapper. Then doing for o in .git/objects/*/*; do cat "$o" | inflate ; echo ""; done lists the contents of all the git objects. Notice that there are no changesets, only full copies of the file you modified at different states. This was surprising to me, since I had a very different model mentally. I still think the DAG of diffs is the better model mentally, but it is worth understanding that this is not what git is actually doing under the hood. It explains issues that arise doing rebases, cherry-picks, etc. I now also understand the motivation behind Pijul. If I understand correctly, Pijul does use a collection of changesets as the underlying model. Like you say, that can be a critical difference.
- falsedan 10y agoThis doesn't seem significantly different to git, from the perspective of a user. Under the hood, I model a git branch as a ref pointing to a commit object in a DAG. In the driver's seat (git log --patch branch..upstream), I think of it as an ordered collection of diffs.
- mempko 10y agoIt is different. When you commit in darcs, you cherry pick as default.
- falsedan 10y agoI don't understand, you will have to use more words. I've never used darcs, and as a git user I don't see how you could cherry-pick by default for commiting. By default, I would say you… create a commit object with the author/date/message/tree/parent metadata recorded in it.
- lvh 10y agoWhen you type git pull, it has a remote and a ref at that remote, and it attempts to merge (ff notwithstanding) the DAG you have with the DAG the remote has. When you type darcs pull, darcs lets you pick and choose which patches (subject to the dependency constraints) you want to pull in. Those patches then get applied however darcs wants to apply them (again, subject to dependency constraints, of cousre). Because you do not necessarily need to pull all of them, you are always "cherry picking" by default. This is different from cherry-picking in git, because when you cherry-pick in git you still have 2+ commits that exist in the context of a DAG; you're just transplanting the contents elsewhere to create a new commit in a different position in the DAG.
- falsedan 10y agoI still don't get it: pulls don't merge DAGs, they add objects and move refs (and maybe merge); every time darcs fans say 'patch' (as a collection of related changes) I think, 'oh like a branch?' This sounds less and less like a tools/implementation thing and more like the default recommended/enforced workflow thing.
- krupan 10y agoThis distinction between commits and patches (I've been following git, hg, and darcs for over a decade) is one I've never quite understood. A patch says, take this original line of code found here and change it into this new line of code. A commit is just a patch that records when in the history you can be sure to find that original line of code. If you take an arbitrary patch and apply it to an arbitrary set of code you might not even be able to find that original line of code. How do darcs and/or pijul solve that problem? Git and mercurial have tools like rebase and cherry pick that allow you to rearrange commits and they can even use three way merge algorithms (because of the DAG) to help recompute the patches for when that original line of code isn't quite what the patch specifies anymore. How are darcs and/or pijul different in that regard?
- lvh 10y agodarcs and pijul have an internal model that tells it where patches can go; it does not suggest patches can go pretty much everywhere (in fact; at any given time it probably only has exactly one idea of which order the patches go in). Once those patches have dependencies, it enforces their order; but e.g. groups of dependent patches can still be transplanted around. The Darcs wiki has some cool graphics around cherry-picking merges that might answer your question better than a paragraph of prose can: http://darcs.net/Using/Model#merging-with-cherry-picking http://darcs.net/Using/Model#merging-with-cherry-picking
- jordigh 10y agoA commit is not a patch. A commit is just often represented as a patch (i.e. a diff), but in general neither git nor hg even save a commit as a patch, except as a minor, optional, and opaque optimisation. What they really save is the entire state of your repo at a particular time, with the hash(es) of the state of the repo just before this one. In the case of git, it saves a tree of hashes that refer to all of the blobs (files) at the current commit. In the case of Mercurial, it saves a manifest of hashes that point to files represented in revlogs. Whenever both git and hg show you a commit as a diff, this involves a computation. They are not merely showing you diffs that they have pre-computed and stored. Bitkeeper does have a weave data structure that more closely resembles patches. It's an encoded set of instructions for transforming one file from one state into another: https://www.bitkeeper.org/src-notes/SCCSWEAVE.html https://www.bitkeeper.org/src-notes/SCCSWEAVE.html This data structure has a big advantage when computing annotations (blames): it's much faster than Mercurial's revlog (which in turn is faster than git's blob-tree-ref structure).
- kibwen 10y agoThat's a bit involved, but I believe that the intent is that Pijul is to Darcs as Git is to Monotone.
- qznc 10y agoI guess, you will see a lot more parallel branches with Pijul compared to git. Assume you change file A, commit, then change file B, and commit. In git there is a dependency from the second to the first commit, because the state of the second is derived from the first one. However, the changes are unrelated because they are in different files. Pijul understands them as parallel unrelated changes (although with different time stamps). (disclaimer: I infer that from using darcs many years ago. I never used Pijul)
- lvh 10y agoWell, it depends. In practice, I think the number of branches is similar. In theory, the number of possible branches is much, much greater (arguably infinite) for git. Commits have their own metadata, so just amending creates a new commit. Patches are immutable, and there's no independent artifact like a commit that incorporates the current set of patches. Furthermore, darcs (and I assume pijul) absolutely let you make multi-file patches.
- tom_mellior 10y ago> How does this compare to git? Apart from the other answers that go into theories of patches vs. commits, I always found Darcs much more intuitive to actually use than Git. It has fewer commands that do more intuitive stuff. To record a patch, you do "record" instead of separate "add" and "commit" steps. To revert some changes you have not recorded and that you want to get rid of, you do "revert" instead of "checkout -- filename". The "diff" command works more intuitively than git's "diff", which you sometimes have to use as "diff --cached" due to its staging model. Another thing is that every branch is a separate copy of the entire source tree in your file system. A drawback is that this can be viewed as wasteful, but the advantage is that it's much much easier to work in parallel branches at the same time since changing the branch is just doing "cd" instead of some boring dance of "stash" and "checkout". You also don't get problems due to files intended for one branch still lying around after a "checkout" to switch to another branch. (I'm assuming that Pijul preserves all or at least most of these properties of Darcs. The docs aren't very exhaustive.)