Show HN: A version control system based on rsync (jamsync.dev)
Hi everyone! I'm trying to create a version control system that solves some of the problems that Git and other version control software has when working in a team. Let me know if you have any feedback!
123 comments
[ 4.5 ms ] story [ 461 ms ] threadYears ago I worked at a company that had a team of front end developers that used Dropbox for version control instead of git. Conflicts were prevented by the default "this file has changed on disk, are you sure you want to save?" warning in their IDEs. It worked incredibly well for that team, and they never suffered a single gitastrophe.
Far too often I find myself making all my changes on my Windows box, or copying them to one destination, the other, or both. Then bug fixing on the local machine as part of my test cycle. Then I have a few moments of confusion when I try to remember what I changed where and how to pull them all back over to my Windows box.
So yeah, something like your proposed tool would be quite useful.
However, it solves the problem of when there are changes on both sides and you want to reconcile them.
why
The most well known project following this is SQLite.
There are many reasons to do this:
- ensuring that the copyright is fully owned
- ensuring security by reducing the likelihood of someone submitting secretly vulnerable code
- not wanting the overhead of running an Open Source Project
- wanting ultimate control on the architecture of the tool
- early stage of a rapidly changing codebase
There is a danger that "gate keeping" the concept of open contribution == open source, reduces the motivation of people to open source their code.
All open source, no matter the contribution policy, should be applauded.
I think it's great to look into possibilities of doing things in a better way, even if the majority of people think the current way is the only correct way.
I love learning new exciting things that I know I’ll use for the rest of my live. C, Vim, Bash, HTML, CSS, JavaScript will all outlive everyone here. It’s a pretty safe bet. I hate the amount of useless knowledge I accumulated for obsolete unexciting things.
I feel like Git is not the final answer to version control, it had a lot of great ideas, but it’s not even good enough for some things and too complicated for most others. My hope is that it becomes like SVN, mostly legacy stuff, and that we can build something new with the lessons learned from Git. I wish Jamsync luck, it looks interesting and I freaking love rsync.
Don't get me wrong, I like both TeX and Git _very_ much. (I even co-authored a LaTeX textbook.) I also have a lot of respect for DEK and LT. But they were trailblazers (especially DEK), and so they did a lot of things not knowing their true impact – and sometimes this means these decisions were far from optimal. (The case of TeX is even worse because the machines of the time were very limited compared to what we have today.)
I'm not using either, because of the git momentum. Only having to know one is nicer than using one for work and one personally.
In my time as a dev I've worked with CVS, SVN, Mercurial, and then git. I can confidently say that no dev I've worked with ever kicked up a fuss when they switched, because each iteration brought improvements.
I would however say that modern devs carry with them modern baggage. There are far too many bootcamps churning out devs who say "this is git, everyone uses it, heres the minimum you need to know". These are the devs who will struggle with this sort of change, it would literally change a magical system they don't fully understand for reasons they may not fully understand.
For everyone,
Eg., suppose t is the reward for exploitation, and r for exploration, and xp is your experience.
Then as xp -> inf, t -> inf and r ->0.
As xp -> 0, the reverse happens: t -> 0 and r -> inf.
Wow. I don't think your experience is the common one. I've been on teams switching to git, and there was always much fussing. Even if the benefits of switching were clear and it was worth it, doesn't mean there won't be pain along the way.
The layering model of merging in both those systems is superior to the standard git merge (rebase is close though). they also made cherry picking a trivial operation compared to git
Going from hg to git has been fairly annoying and... I'm not really convinced it's any better. Or maybe even at parity.
Would it be better for projects with large static/binary assets, such as game dev or CAD?
I'm looking for a good tool for 3D CAD version control because the available ones are all expensive and focus on features for managers, not engineers (like approval workflows). I was excited by Jamsync, but I don't think this will work well for a few reasons. First, CAD software generally modifies every file you open, unless it is read-only. This is mainly because even rotating a model causes a file change. Second, it's really common for multiple engineers to work in the same assembly, even if they are working in different parts. Third, merging of the CAD files, which are binary, isn't usually possible even when using the same vendor for both CAD and version control. So all you can do is select a version to keep, you can't merge. It's annoying because often one person's real work is overwritten just because someone else had a stale copy of an assembly file, and saved over the real work with something trivial like a view rotation. Only there's no easy way even compare two versions so the most common scenario is redoing the work. CAD won't generally continuously load any changes like in the example on your website, because engineers have assemblies open, for the entire day, with all or most files in a project, and these are loaded into memory once and locked on the disk.
All this means that one feature is 100% required: (a) explicit checkout and checkin of the files you want to work on, only allowed by one user at a time. It's almost a requirement (b) to do this with a plugin in the CAD software itself, because hierarchies within CAD assembly files are used to select, open, etc files, and because CAD files are often just names with a consecutive numbering scheme. It's quite painful to have to use a different interface to locate and checkout/checkin files.
If you can offer these two things you may have a decent market for small companies using CAD. Self-hosting (c) is a requirement for many industries. A file viewer (d) is nice to have but not at all required, and every other software attempts to add JIRA-type features (e) which frankly just becomes another place other than the correct place to document things.
The only software I've seen which really hit the mark was grabcad workbench, which is unfortunately being discontinued[1]. It did just a, b, and d and it was free too!
The offerings from actual CAD vendors are way too heavy, need dedicated roles to maintain them, and cost more than CAD licenses. Kenesto[2] does a, b, d and and Bild[3] does a, d only. Kenesto looks good but I've heard complaints that it feels barely maintained. Bild looked promising but it's slow and not only is it lacking b, a plugin for CAD, you have to use its webview application which offers no search, preview or sorting options so you have spend your time scrolling through a list of files. And of course, both offer way too many unwanted features. Everyone selling version control software for CAD doesn't seem to realize that we don't want to them to compete with Siemens on features. We want a few features done well, and already have tools or workflows for tickets, approvals, commenting, etc.
[1] https://blog.grabcad.com/blog/2022/08/09/a-fond-farewell-to-...
[2] https://www.kenesto.com/buynow
[3] https://www.getbild.com/plans
https://github.com/gotvc/got
The algorithms it uses are superior to rsync and git in a few ways. It comes short on features, especially for software development compared to Git. The motivation is more for personal file storage.
I notice you're using Go and AGPL licensed, so you could borrow any of Got's libraries without issue. (Got is GPL licensed.) Definitely reach out in a GitHub issue.
INET256 solves that problem nicely. If you have access to an INET256 network, then all you have to do is swap addresses and two Got instances can communicate.
https://github.com/inet256/inet256
Also, end-to-end encryption is table stakes. Any data that leaves the user needs to be encrypted in transit, and if it hangs around away from the user, at rest.
Got stores data in a probabilistic tree (GotKV[0]). The number of nodes before you get to data will scale logarithmically with the size of the entire filesystem, not the depth of a specific object.
Then there is the issue of large files. A file in Git is always 1 blob. Syncing a large blob is not easy because if you are interrupted and have to restart, you have lost all your progress. You can't verify the hash of a blob until you have the whole thing. Got has a maximum blob size, so you'll only be buffering <2MB at a time before you can verify that the blob is correct. If a transfer is interrupted, the most you'll have to repeat is one blobs worth, plus any tree nodes above that blob.
Compared to rsync, Got uses variable size chunks and a faster content defined chunking algorithm, recently featured here on HN[1]. I haven't thought about if variable vs fixed chunks is better for file transfer, but for version control, the higher chance of convergence is important. It means you have better deduplication.
[0] https://github.com/gotvc/got/tree/master/pkg/gotkv
[1] https://news.ycombinator.com/item?id=34303497
[0] https://github.com/gotvc/got/tree/master/pkg/gotkv/ptree
Here "probabilistic" just refers to a way of balancing a tree. Rather than having a set of rules to keep the tree balanced, like with a btree or red-black tree, balancing decisions are made pseudorandomly. The result is that the tree is very likely to be balanced, and is unlikely to be unbalanced.
In the case of GotKV's tree: the entries are stored together in a stream, and for each entry a hash is computed. If that hash is lower than a certain value then the entry is considered a split point, and a tree node is created. So now we have a stream of entries, divided probabilistically into sections. Each section is a tree node. Now take references to those nodes and turn them into entries, and repeat the process, so you have fewer nodes. That continues until you have one node, which is the root. This technique is very similar to content defined chunking, and some probabilistic trees are implemented using content defined chunking on their record format, rather than a pseudorandom value calculated per entry, as in GotKV.
For those unfamiliar with probabilistic data structures, I highly recommend trying to understand skip-lists first. At least why they are balanced.
https://en.wikipedia.org/wiki/Skip_list
As an aside, one of the neat things about GotKV is that the keys are delta-encoded. Adding or removing a prefix from every key in the tree is a constant time operation. This might be obvious to some of the database folks out there, but it's a fun mind-blower if you haven't encountered the technique before.
https://en.m.wikipedia.org/wiki/Treap
I keep trying to find a use for treaps, but haven't had a project that needed it. In particular, the value of a balanced tree is in consistent cost of lookups for arbitrary elements. But if you are mixing entries that are accessed often with those that are not, having an 8:1 access time ratio between the two would be a feature not a bug.
edit: looks like at least one other has has the same idea https://github.com/lthibault/treap
Does Jamsync have 3-way merging (e.g. of local and remote changes on top of a shared ancestor)?
However I can see where a sort of "checkpoint" feature before performing a "hold my beer" change makes sense. A commit in some sense. `jam checkpoint` ... code ... `jam revert`
You should just be coding, and when the thing your are coding is done just do a single "squash merge (in git speak)" to the main branch.
you're being too hard on git. large teams sharing code in previous SCCS rcs's (haha) would frequently encounter locks and not be able to "just code" but would need to negotiate with teammates or complain to committees. The features of git allow you to "just code" in a group environment, but it moves conflicts to a different link in the chain. The interplay between changes sprinkled across a codebase need to be negotiated in any system, but git generally allows you to "just code" till it makes sense or is convenient to negotiate
maybe "git with wimpy locks" would be a nice feature. if you're editing files, the center node could keep track of that, and if I go to edit one of those files, I could be told that you've already edited it. I could forge ahead ("break the lock" and you would get notice) or I could ask you. It doesn't resolve all problem between prickly developers with different styles of workflow, but it would increase communication at little cost.
e.g. does adding a space at the start of a file causing all of the blocks to be misaligned?
* I think this makes two devs changing the file basically unusable as you're changing the file and potentially the same line simultaneous which could cause me to overwrite your changes without realising
* It still presumable doesn't get away from the fact I can edit the file with the jam command not running then run it after in which it'll just overwrite my local changes onto the remote without merging
* What does it do if my editor has changes in the change buffer that aren't saved and an update comes in on the same line, then I save. Will my now out of date change buffer overwrite the server version ?
I don't think you can do away with merging and merge conflicts it's a vital part of source control so that two devs can work on the same file simultaneously.
How often does the thing sync, none of the demos really show this. The demo's showed the thing running very often i.e. every few seconds. Does that mean if I'm making large changes to a file it automatically upload every time I save the file ? I definitely do not want that as typically when editing code as I edit I will save something that is in a partially broken / incomplete state. It also precludes the main CI/CD workflows which will normally trigger from a dev uploading something they think will work.
Where is the actual source, the source page links me to here: https://jamsync.dev/download
This just gives a link to a .zip which is presumably out of date now. I presume you are trying to self host this but since you haven't ironed out the details it would be better to use an open source code tool like github /gitlab ...etc for the time being.
You are allowing me to register / login to an "account" on something with basically no terms of service or privacy policy. Not only are you not GDPR compliant but more importantly at the moment you are not limiting your liability! The fact you've stuck this up without limiting your liability you are now partially liable for whatever stuff people are putting up on here baffles me. Seriously for your own good please get some terms of service with at least limitation of liability.
You'll have to also sort the problem of copyright as I wouldn't push code to a service that attempts to claim any copyright of that which I assume you're not doing but I would need that in writing.
Given the frequency of commits that this solution will introduce you'll need to offer way more than 5GB of hosting.
How will that version slider work when I have 500k commits. Even squashing branches, the repo I'm working on at the moment has 10k commits. This is a team of about 30-40 devs and each day is about 15ish PRs. With Jamsync syncing every save I could easily see this going up to millions of commits.
Causing a conflict will cause a .jamdiff file to be written out on the next sync with the remote changes and I'm planning on adding branches in the next update which will make how this works more clear. There's still a concept of parallel editing, since features cannot be developed/tested simultaneously without breaking. Also, anytime there's a conflict, we can just make a new branch and ask the developer to merge or keep working on the new branch.
The client will watch your file system for changes and hold a gRPC stream open for remote changes. If you don't want to sync your changes, you don't have to leave the command running. CI/CD support will come later.
I'll be compliant with regulations soon, but I'm not really expecting people to use this yet. I mostly wanted to release the source and see what people thought of the project. I am using GDPR compliant Plausible analytics if that makes you feel better!
Thanks for the suggestion on the source, the zip file is up-to-date and is part of my build process. I might host on Github in the future but really wanted to make this the source of truth. My goal of open-sourcing is not to get contributors, but to give back to people who want to view the code and self host.
As far as scaling issues go, I'm planning on using an approach similar to https://madebyevan.com/algos/log-spaced-snapshots/ but I'm still figuring out the best way to handle commits.
You know I can see you post history right ? 5 months ago you posted about this:
https://news.ycombinator.com/item?id=32546472
Please don't lie to me...
> Also, anytime there's a conflict, we can just make a new branch and ask the developer to merge or keep working on the new branch.
Ok so this tool doesn't solve the problem of merge conflicts.
> The client will watch your file system for changes and hold a gRPC stream open for remote changes. If you don't want to sync your changes, you don't have to leave the command running. CI/CD support will come later.
Eek then the thing isn't consistent if two of us are using this tool and I keep it open all the time I'll generate a lot of commits. If you only run the command sporadically you'll generate significantly less.
> I'll be compliant with regulations soon, but I'm not really expecting people to use this yet. I mostly wanted to release the source and see what people thought of the project. I am using GDPR compliant Plausible analytics if that makes you feel better!
I feel nothing only pain :-). I note that you have missed out my comments on limiting your liability. Since you seem to be deliberately doing that I'll give you some advice. There are some heinous people online who will use this service in it's current form to share some vile shit with each other. At the moment you are liable for that. IANAL.
> Thanks for the suggestion on the source, the zip file is up-to-date and is part of my build process. I might host on Github in the future but really wanted to make this the source of truth. My goal of open-sourcing is not to get contributors, but to give back to people who want to view the code and self host.
Erm you know I can see the source. You have the code stored in a private repo in github.
To be blunt I don't trust you anymore.
How do you review changes easily?
It seems like a lot is actually missing. Rolling hashes over blocks is not exactly revision control.
I don’t see any fundamental reason why git or, even 3p tooling for git, couldn’t support this use case using something like private, ephemeral, auto-synced branches.
- [0] https://engineering.fb.com/2022/11/15/open-source/sapling-so...
can't git do this with a fork, and you put all your devices on the fork, then merge the fork when you're ready?
It’s possible, but it’s some steps you need to take. You can’t just get up from your pc, take your laptop and start working.
Local changes in gut feel like in the pre-Dropbox era, something you need to copy on your own.
Nowadays I use Syncthing for the same purpose (I learned about Syncthing when I did a Show HN for gut). Dropbox works reasonably well, too.
1. Performance was never more than tolerable
2. Invite only access
3. Invites didn't go out immediately, just added people to a pool of potential future invites
A product that required the network effect of a large connected userbase to succeed only had random individuals with access. Literally no one I invited and would have used it with got in, and I was in one of the first couple batches of public users to get access. A spectacular self-own on Google's part with that rollout.
Ultimately, the priorities of Fossil are going to be different than Jamsync, since Jamsync is not decentralized. Being centralized means that we'll be able to do some different things, like live file editing, but with some downsides related to replication and distribution.
Very interesting.
Multiple times I've been on teams with spray and pray type developers who commit more frequently. Begetting more chaos and rework, of course. But great for apparent "velocity".
Whereas I tend to work slow and deliberate. Doing old timey stuff like unit tests and verifying my code works before committing. Which then puts the onus of resolving merge conflicts onto me. Which then delays my commits. Which means more even more merge conflicts.
A vicious cycle.
It'd be cool if better tooling, such as jamsync, helped mitigate the penalty for doing good work.
Would Jamsync solve this problem?
https://beeznest.wordpress.com/2005/02/03/rsyncable-gzip/
1) I recall a comment a while back from the xdelta author about how most history tools store a sequence of changes from nothing (as it sounds like yours does), but this isn't ideal since usually you want a recent version which then needs to be produced from the potentially long sequence of changes. Caching various revisions could help in your case but that is less than ideal when the files are large.
2) It isn't clear how you go from live editing type thing to revision control. If you haven't yet, you might want to look at the Aegis paper[1] (it is short) for a quick overview of the framework it used to form a revision control system from a collection of more specific tools that could be customized. That type of framework might go well with your rapid branch synchronization. Sadly the author, Peter Miller[2], died in 2014. As far as I know no one picked up development (it isn't the easiest name to search for :/). The User Guide [3] from the documentation page [4] gives a bit more info about the model.
[1] https://aegis.sourceforge.net/auug93.pdf
[2] https://en.wikipedia.org/wiki/Peter_Miller_(software_enginee...
[3] https://aegis.sourceforge.net/user-guide.pdf
[4] https://aegis.sourceforge.net/documents.html
1) Agreed, caching might not be great for large files. I don't think this is the only way though. I think there is another approach, that I haven't explored, which is storing a pointer to the last known Data block in each Range block. This means that you can just jump directly to the actual data without having to go through this regeneration or caching process. The space cost of this would be pretty low, one int per block, but it would mean that you wouldn't need to iterate through every change. Still figuring this out though and caching would be the best option if this doesn't work.
2) Yes I haven't totally figured this out yet. I'll give this a look, thanks!