Version control systems are software tools that help developers track and manage changes to source code. There are several different version control systems available, each with its own set of features and capabilities. Some popular version control systems include Git, Mercurial, and Subversion. All of these version control systems are designed to help developers collaborate on projects, track changes to their code, and maintain a history of their work. In this post I will talk about a new player on the field, developed internally by Meta – Sapling.
Why do we need Sapling?
Given that we already have Git, Mercurial, and Subversion, among others, it is hard to see why exactly do we need yet another version control system. As Meta puts it, Sapling is focused specifically on usability and scalability, mentioning that common workflows are simpler and recovering from mistakes is way easier. Additionally, Meta has designed Sapling and Sapling server to be highly scalable, being able to handle 10’s of millions of files.
Sapling SCM (source code management) consists of three parts:
- Sapling CLI, a command-line tool that users use to clone repositories, perform commits, and push their changes to the server
- Sapling Server, a server-side backend application, that hosts and manages repositories.
- Sapling Virtual Filesystem, a filesystem used by Sapling to speed up the workflow.
As of late 2022, only Sapling CLI is released, while Sapling Server and Virtual Filesystem are not yet available for the public. The good news is that you can use Sapling with your existing Git repositories, and it even integrates nicely with GitHub!
How to install Sapling
To get Sapling, you can follow the official installation guide, available here. For your convenience, here are the steps to installing Sapling on your system:
For macOS: install from Homebrew using this command:
$ brew install sapling
For Windows: download the latest version ZIP and run these commands in PowerShell:
PS> Expand-Archive NAME_OF_DOWNLOADED_ZIP 'C:\\Program Files' PS> setx PATH "$env:PATH;C:\\Program Files\\Sapling" -m
Note that to use all the features available, you also need to have Git and Node installed.
For Ubuntu 22.04: run these commands:
$ curl -L -O <https://github.com/facebook/sapling/releases/download/0.1.20221213-150011-h9b0acf12/sapling_0.1.20221213-150011-h9b0acf12_amd64.Ubuntu22.04.deb> $ sudo apt install -y ./sapling_0.1.20221213-150011-h9b0acf12_amd64.Ubuntu22.04.deb
For Ubuntu 20.04: run these commands:
$ curl -L -O <https://github.com/facebook/sapling/releases/download/0.1.20221213-150011-h9b0acf12/sapling_0.1.20221213-150011-h9b0acf12_amd64.Ubuntu20.04.deb> $ sudo apt install -y ./sapling_0.1.20221213-150011-h9b0acf12_amd64.Ubuntu20.04.deb
For other Linux: you can install Sapling from Homebrew if you have it:
$ brew install sapling
If you do not have Homebrew, your only other option is building it from source, for now.
How to set up Sapling
After you have installed Sapling on your system,
sl command should be available in your terminal. To start using it, you first need to configure your identity. It is used to authorize your commits and you can set it up like this:
$ sl config --user ui.username "YOUR NAME <YOUR EMAIL>" # for example... $ sl config --user ui.username "Michael Krasnov <[email protected]>"
After running this, Sapling should be ready to go. However, if you want to use Sapling with GitHub, you need to set up GitHub authentication for Sapling. The recommended way of doing this is installing the GitHub CLI (
gh) and running this command:
$ gh auth login --git-protocol https
In my opinion, it is an overkill having 2 tools for working with GitHub repos. You can make it work without GitHub CLI, if you create a personal access token and give it to Sapling when asked.
How to use Sapling
Now let’s go through some basic workflows to get a feel of using Sapling in real projects. I have created a fork of the Redux repo on my Github account to play around with. Let’s start with cloning repos from Github. To clone a repo from Github using Sapling, run this command:
$ sl clone <GITHUB REPO URL> # for example... $ sl clone <https://github.com/r3dm1ke/redux>
We get an output that looks familiar to anyone who had used Git in the past:
remote: Enumerating objects: 20640, done. remote: Counting objects: 100% (7/7), done. remote: Compressing objects: 100% (6/6), done. remote: Total 20640 (delta 1), reused 1 (delta 1), pack-reused 20633 Receiving objects: 100% (20640/20640), 23.78 MiB | 2.27 MiB/s, done. Resolving deltas: 100% (13183/13183), done. From <https://github.com/r3dm1ke/redux> * [new ref] fbfe51458ca2addf97f426d505bf2c27503a5ff1 -> remote/master 452 files updated, 0 files merged, 0 files removed, 0 files unresolved
Now you can
cd into your cloned project and verify everything worked by running the
$ sl @ fbfe51458 Dec 15 at 10:20 65634467+Ahmed-Hakeem remote/master │ change reducer type validation place (#4452) ~
By default, the
sl command shows us the last commit in the repo, as well as all of your own commits in your stack (more on that later). To see complete commit history in Sapling, run this command:
$ sl log changeset: fbfe51458ca2addf97f426d505bf2c27503a5ff1 (@) user: Hakeem <[email protected]> date: Thu, 15 Dec 2022 10:20:08 -0500 summary: change reducer type validation place (#4452) changeset: a0754310222ad61bde675078963afb7fc038d5d7 user: Mark Erikson <[email protected]> date: Mon, 05 Dec 2022 10:49:27 -0500 summary: Merge pull request #4448 from jshoung/docs/remove-dead-link changeset: 89104853174e62de8ebbca4881ea14a04399f4e2 user: julian <[email protected]> date: Mon, 05 Dec 2022 10:00:58 -0500 summary: Remove link to deleted tweet changeset: 9be553a2c5ba04d9d769f31e25a6dc93deb334cf user: Mark Erikson <[email protected]> date: Wed, 30 Nov 2022 10:12:49 -0500 summary: Merge pull request #4447 from mariussd/patch-1 ...
Let’s now see how committing and pushing works in Sapling. Firstly, I will make my changes to the project:
$ echo "PS Redux is awesome" >> README.md $ touch newfeature.js $ echo "TODO: write new feature" >> newfeature.js $ sl status M README.md ? newfeature.js
sl status command works the same way as
git status . You can see that Sapling sees that we modified
[README.md](<http://README.md>) and created
newfeature.js. The question mark next to
newfeature.js means that we did not
add it yet:
$ sl add newfeature.js $ sl status M README.md A newfeature.js
We can go ahead and commit the changes. To commit changes in Sapling, run this command:
$ sl commit -m "Initial work for my new feature" $ sl @ b6989309b 2 seconds ago mihalKrasnov ╭─╯ Initial work for my new feature │ o fbfe51458 Dec 15 at 10:20 remote/master │ ~
You can see our new commit in the graph view. To show you more features, let’s go ahead and add some more commits:
$ echo "Developed new exiting feature!" >> CHANGELOG.md $ sl commit -m "Updated changelog" $ echo "const feature = () => console.log('abacaba')" >> newfeature.js $ sl commit -m "Feature implementation" $ sl @ 8c9eb0035 1 second ago mihalKrasnov │ Feature implementation │ o e445f1379 87 seconds ago mihalKrasnov │ Updated changelog │ o b6989309b 3 minutes ago mihalKrasnov ╭─╯ Initial work for my new feature │ o fbfe51458 Dec 15 at 10:20 remote/master │ ~
Now you can see 3 commits in your stack. Notice that the most recent commit is marked with an
@. You can move in your stack using commands
sl prev and
$ sl prev 1 files updated, 0 files merged, 0 files removed, 0 files unresolved [e445f1] Updated changelog $ sl o 8c9eb0035 4 minutes ago mihalKrasnov │ Feature implementation │ @ e445f1379 5 minutes ago mihalKrasnov │ Updated changelog # NOTICE THAT @ IS NOW HERE │ o b6989309b 7 minutes ago mihalKrasnov ╭─╯ Initial work for my new feature │ o fbfe51458 Dec 15 at 10:20 remote/master │ ~ $ sl prev 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ sl o 8c9eb0035 4 minutes ago mihalKrasnov │ Feature implementation │ o e445f1379 5 minutes ago mihalKrasnov │ Updated changelog │ @ b6989309b 7 minutes ago mihalKrasnov ╭─╯ Initial work for my new feature # AND NOW HERE │ o fbfe51458 Dec 15 at 10:20 remote/master │ ~ $ sl next 2 2 files updated, 0 files merged, 0 files removed, 0 files unresolved [8c9eb0] Feature implementation $ sl @ 8c9eb0035 4 minutes ago mihalKrasnov │ Feature implementation # AND BACK UP │ o e445f1379 5 minutes ago mihalKrasnov │ Updated changelog │ o b6989309b 7 minutes ago mihalKrasnov ╭─╯ Initial work for my new feature │ o fbfe51458 Dec 15 at 10:20 remote/master │ ~
Now let’s say that I am dissatisfied with the implementation of my feature and would like to undo my last commit. To undo your last commit in Sapling, run this command:
$ sl uncommit $ sl # FIRST COMMIT GONE! @ e445f1379 9 minutes ago mihalKrasnov │ Updated changelog │ o b6989309b 11 minutes ago mihalKrasnov ╭─╯ Initial work for my new feature │ o fbfe51458 Dec 15 at 10:20 remote/master │ ~ $ sl status M newfeature.js # CHANGES ARE UNTOUCHED
Lastly, after fixing the last change, we want to push our changes and open a pull request. Since Sapling integrates with GitHub, this is very easy: just run this command to push and open a pull request:
$ sl pr pushing 3 to <https://github.com/r3dm1ke/redux> created new pull request: <https://github.com/r3dm1ke/redux/pull/1> created new pull request: <https://github.com/r3dm1ke/redux/pull/2> created new pull request: <https://github.com/r3dm1ke/redux/pull/3>
You can see that Sapling created 3 pull requests, one for each commit. This seems counterintuitive and downright criminal, especially when using GitHub. In fact, this is meant to be used with ReviewStack, a UI for browsing GitHub pull requests made by Meta. You can read more about it here.
One more useful feature is viewing PR statuses from the command line. Once you have opened your pull requests, run
sl ssl to get their statuses:
$ sl ssl @ b615c1183 7 minutes ago mihalKrasnov #4458 Closed ✓ │ Implementation │ o e445f1379 17 minutes ago mihalKrasnov #4457 Closed ✓ │ Updated changelog │ o b6989309b 19 minutes ago mihalKrasnov #4456 Closed ✓ ╭─╯ Initial work for my new feature │ o fbfe51458 Dec 15 at 10:20 remote/master │ ~
How to use Sapling UI
Sapling is not a purely CLI program, but it also comes with a GUI. Using a GUI for version control can be more user-friendly and easier to use than command-line interfaces, and may offer visual features such as graphical representations of branches and commit histories. However, GUI apps may be slower and less customizable than CLIs. To open Sapling’s GUI, run this command:
$ sl web started a new server access Sapling Web with this link: <http://localhost:3011/?token=>
If you open this URL, you will see the UI:
Using this UI, you can see the commit history, open PRs, diffs, perform amends and commits, and sync changes with the server. However, I did not find it particularly useful, and would continue to use GitKraken for all things GUI.
Key differences from Git
Sapling is a version control system that shares many characteristics with Git, such as being distributed, using hash-addressed commits, and having branches called “bookmarks,” as well as a similar workflow involving clone, pull, push, commit, and rebase. However, there are also several notable differences between the two systems.
- Local branches are not required: in Git, your repository is defined by the presence of local branches, and you are required to be on a local branch while working. In contrast, Sapling allows you to use local bookmarks (the equivalent of Git branches) if you wish, but they are not necessary. Instead, you can simply reference your commits by their hash values, which are visible in the “smartlog” display.
- Partial downloads: when you clone or pull from a repository in Git, you typically retrieve all new data. In Sapling, a clone or pull will only fetch the main branches of the repository, with other branches being fetched as needed.
- Undo features: this feature certainly will be loved by the community. Sapling offers dedicated “uncommit,” “unamend,” “unhide,” and “undo” commands for reversing common actions, and the “undo -i” command allows you to preview the effects of multiple undos before applying them.
- No staging area: Git requires you to add changes to a staging area before committing them, but Sapling does not have a staging area. If you want to commit or amend only part of your changes, you can use an interactive option to select the specific changes or create a temporary commit and amend it before folding it into the real commit.
- Built-in UI: this would be a welcomed feature by those who do not like using the CLI
Personal pros and cons
I would like to finish with a list of my personal pros and cons after using Sapling for some time. It’s worth noting that these are just some potential pros and cons, and the actual benefits and drawbacks of using Sapling will depend on your specific needs and use case.
- Sapling does feel like a breath of fresh air after using Git for many years. The workflows (at least the ones I use) seem simpler, Sapling feels a little faster, and the commands are more intuitive
- Undo commands are lifesavers, and I am way more confident using advanced VCS features in Sapling when I know how easy it is to undo everything
- The lack of branching seems counterintuitive to me. When a lot of people are working on one repo, it is very easy to see all the branches and switch between them and rebase other changes onto your branch. Maybe this will come with experience, but for now I prefer Git’s branching to Sapling’s bookmarking
- One PR per commit: while this may make sense when using Sapling Server or ReviewStack, it is useless with vanilla GitHub
- Sapling is still in early development, so it lacks many features that Git has, for example Git hooks (both client and server side), community support, tools and UIs.
I will not be switching from Git to Sapling just yet, but it is very exiting and I am glad there is some competition stirring in the VCS world. I will also be eagerly waiting for the release of Sapling Server and Virtual Filesystem, and present my review for them as well. I hope you liked my article, and do not forget to subscribe to read more of them!