This repo uses Sapling for version control. The CLI
command is sl, not git. Never run git commands in this repo. See the
basic commands overview
for a quick reference.
-
No staging area. All tracked files are included when you
sl commit. Usesl add/sl forgetto change what is tracked. -
Smartlog.
sl smartlog(or justsl) is the most important command — it replacesgit logwith a succinct view of only your relevant commits. It shows:- Important details per commit: short hash, date, author, bookmarks, title.
- Which commits are old/landed (marked
xwith "Landed as …"). - Your current position (
@). - The graph relationship between commits.
- The location of
mainand other remote bookmarks. - Your not-yet-pushed commits.
The dashed line on the left represents
mainand elides thousands of commits to show just the ones relevant to you:$ sl o 5abffb8 Wednesday at 09:39 remote/main ╷ ╷ @ 824cbba 13 minutes ago mary ╷ │ [eden] Support long paths in Windows FSCK ╷ │ ╷ o 19340c0 Wednesday at 09:39 mary ╷ │ [eden] Close Windows file handle during Windows Fsck ╷ │ ╷ o b521925 Wednesday at 09:39 mary #12 ╭─╯ [eden] Use PathMap for WindowsFsck │ o 2ac1861 Wednesday at 05:00 remote/stable ╷ ╷ o 339f936 Jul 15 at 11:12 mary ╷ │ debug ╷ │ ╷ x 2d4fbea [Landed as 04da3d3] Jul 15 at 11:12 mary #11 ╭─╯ [sl] windows: update Python │ ~sl ssl(super smartlog) fetches extra info from GitHub (PR status, CI checks).sl webopens an interactive GUI that auto-refreshes and supports drag-and-drop rebasing. -
Stacks. First-class support for editing commit stacks with
amend,fold,split, andabsorb. -
Undo. Most commands can be reversed with
sl undo/sl redo.
sl goto COMMIT (or sl go) checks out a commit. The argument can be:
- A short unique-prefix hash (e.g.
b84224608) - A full 40-character hash
- A remote bookmark name (
mainorremote/main) - A local bookmark name
- A revset expression (see below)
Next / Prev — move up and down a stack without remembering hashes:
sl prev # check out the parent commit
sl next # check out the child commit
sl prev 2 # move down 2 commits
sl next 3 # move up 3 commits
If a commit has multiple children or parents, next/prev will prompt you to
choose.
Top / Bottom — jump to stack endpoints:
sl goto top # jump to the topmost commit in the current stack
sl goto bottom # jump to the bottommost commit in the current stack
Revsets are a query language for specifying commits. Any command that takes a commit argument accepts a revset expression. Common examples:
| Revset | Meaning |
|---|---|
. |
Current commit (working copy parent) |
.^ or .~1 |
Parent of current commit |
.~2 |
Grandparent of current commit |
19340c0~-1 |
Child of 19340c0 |
draft() |
All local (unpushed) commits |
ancestors(.) |
Current commit and all its ancestors |
ancestor(., main) |
First common ancestor of . and main |
pr42 |
Pull request #42 (GitHub repos) |
Run sl help revisions for the full language reference (operators, predicates,
and more examples).
| Git | Sapling |
|---|---|
git status |
sl status / sl st |
git diff |
sl diff |
git add FILE |
sl add FILE |
git commit -m "msg" |
sl commit -m "msg" |
git commit --amend |
sl amend |
git checkout COMMIT |
sl goto COMMIT |
git log |
sl (smartlog) |
git stash / git stash pop |
sl shelve / sl unshelve |
git rebase main |
sl rebase -d main |
git reset --soft HEAD^ |
sl uncommit |
Unlike git log, sl log is rarely needed for day-to-day work (smartlog covers
that). It is useful for investigating deeper history:
sl log -l 10 # last 10 commits in the repo
sl log file.c # commits that touched file.c
sl log -f file.c # same, following renames/copies
sl log -L file.c,13:23 -p # commits touching lines 13–23 with patches
sl log -Mp lib/ # commits touching lib/, excluding merges, with diffs
sl log -k "search term" # commits matching a keyword (case-insensitive)
sl log -u alice # commits by a specific user
sl log -r "a21ccf and ancestor(release_1.9)" # check if a commit is in a release
Notable flags: -p/--patch (show diff), --stat (diffstat summary),
-G/--graph (ASCII DAG), -T/--template (custom output format),
--removed (include file removals).
sl journal (or sl jo) shows the history of your previously checked-out
commits — useful for finding a commit you were on earlier or recovering hidden
commits:
sl journal # history of the current checkout position
sl journal --all # history for all bookmarks and current commit
sl journal --verbose # include previous hash, user, timestamp
sl journal -c # show full commit metadata for each entry
sl journal -c --patch # show commit metadata with diffs
Run sl help COMMAND for any command's full usage. For deeper topics:
| Help topic | What it covers |
|---|---|
sl help revisions |
Revset language: operators, predicates, examples |
sl help templating |
Customizing log/smartlog output with templates |
sl help filesets |
Selecting files by characteristics (set:) |
sl help patterns |
File name pattern syntax (glob, re:, path:) |
sl help glossary |
Definitions of common Sapling terms |
The primary push/pull workflow is make sync from the repo root. It:
- Runs lint to ensure nothing is broken
- Rebases upstream changes under your local commits
- Restacks orphaned draft commits if needed
- Pushes draft commits on top of
mainto the remote
Use make sync when you sit down (to pull latest) and before you get up (to
push your work). It only restacks and pushes draft commits on top of main.
The full script (hack/repo_sync.sh):
#!/bin/bash
set -e
# pass lint before interacting with upstream
make lint
# rebase upstream over local
sl pull --rebase -d main
# restack only when the commit graph has orphans — draft commits whose
# parent was rewritten (amend/absorb) but whose children weren't rebased.
# "children(obsolete()) - obsolete()" finds exactly these stragglers.
needs_restack=$(sl log --rev "children(obsolete()) - obsolete()" -T "{node}\n" 2>/dev/null | head -1)
if [ -n "$needs_restack" ]; then
sl restack
fi
# push when there are draft commits on the stack above main
# (draft() & ancestors(.) & descendants(main)). Side-branch drafts are
# ignored so they don't trigger a push.
draft_on_main=$(sl log --rev "draft() & ancestors(.) & descendants(main)" -T "{node}\n" 2>/dev/null | head -1)
if [ -n "$draft_on_main" ]; then
sl push --to main
fiIf this script doesn't exist in the repo, add it & the root level sync make target.
For anonymous feature branches (work not on top of main), use sl directly:
sl goto <rev>to switch to the branch tipsl rebase -s <tip> -d mainwhen ready to landsl push --to <remote-branch>to share without landing