1# Git to Fossil Translation Guide
2
3## Introduction
4
5Fossil shares many similarities with Git.  In many cases, the
6sub-commands are identical: [`fossil bisect`][fbis] does essentially the
7same thing as [`git bisect`][gbis], for example.
8
9This document covers the cases where there is no simple 1:1 mapping,
10usually because of intentional design differences in Fossil that prevent
11it from working exactly like Git. We choose to explain these differences
12rather than provide a simple “translation dictionary,” since to
13understand the conversion, you need to know why the difference exists.
14
15We focus on practical command examples here, leaving discussions of the
16philosophical underpinnings that drive these command differences to [another
17document][fvg]. The [case studies](#cs1) do get a bit philosophical, but
18it is with the aim of illustrating how these Fossil design differences
19cause Fossil to behave materially differently from Git in everyday
20operation.
21
22We present this from the perspective of Git users moving to Fossil, but
23it is also possible to read this document as a Fossil user who speaks
24only pidgin Git, who may often have questions of the form, “Now how do I
25do X in Git again?”
26
27This document’s authors are intimately familiar with Fossil, so it is
28difficult for us to anticipate the perspective of people who are
29intimately familiar with Git. If you have a lot of prior Git
30experience, we welcome your contributions and questions on the [Fossil
31Forum][ffor].
32
33While we do try to explain Fossil-specific terminology inline here
34as-needed, you may find it helpful to skim [the Fossil glossary][gloss].
35It will give you another take on our definitions here, and it may help
36you to understand some of the other Fossil docs better.
37
38[fbis]:  /help?cmd=bisect
39[gbis]:  https://git-scm.com/docs/git-bisect
40[ffor]:  https://fossil-scm.org/forum
41[fvg]:   ./fossil-v-git.wiki
42
43
44<a id="mwd"></a>
45## Repositories And Checkouts Are Distinct
46
47A repository and a check-out are distinct concepts in Fossil, whereas
48the two are collocated by default with Git. This difference shows up in
49several separate places when it comes to moving from Git to Fossil.
50
51
52
53#### <a id="cwork" name="scw"></a> Checkout Workflows
54
55A Fossil repository is a SQLite database storing the entire history of a
56project. It is not normally stored inside the working tree.
57A Fossil working tree — also called a check-out — is a directory
58that contains a snapshot of your project that you are currently working
59on, extracted for you from the repository database file by the `fossil`
60program.
61
62Git commingles these two by default, with the repository stored in a
63`.git` subdirectory underneath your working directory. There are ways to
64[emulate the Fossil working style in Git](#worktree), but because they’re not
65designed into the core concept of the tool, Git tutorials usually
66advocate a switch-in-place working mode instead, so that is how most
67users end up working with Git. Contrast [Fossil’s check-out workflow
68document][ckwf] to see the practical differences.
69
70There is one Git-specific detail we wish to add beyond what that
71document already covers. This command:
72
73        git checkout some-branch
74
75…is best given as:
76
77        fossil update some-branch
78
79…in Fossil. There is a [`fossil checkout`][co] command, but it has
80[several differences](./co-vs-up.md) that make it less broadly useful
81than [`fossil update`][up] in everyday operation, so we recommend that
82Git users moving to Fossil develop a habit of typing `fossil up` rather
83than `fossil checkout`. That said, one of those differences does match
84up with Git users’ expectations: `fossil checkout` doesn’t pull changes
85from the remote repository into the local clone as `fossil update` does.
86We think this is less broadly useful, but that’s the subject of the next
87section.
88
89[ckwf]: ./ckout-workflows.md
90[co]:   /help?cmd=checkout
91
92
93#### <a id="pullup"></a> Update vs Pull
94
95The closest equivalent to [`git pull`][gpull] is not
96[`fossil pull`][fpull], but in fact [`fossil up`][up].
97
98This is because
99Fossil tends to follow the CVS command design: `cvs up` pulls
100changes from the central CVS repository and merges them into the local
101working directory, so that’s what `fossil up` does, too. (This design
102choice also tends to make Fossil feel comfortable to Subversion
103expatriates.)
104
105The `fossil pull` command is simply the reverse of
106`fossil push`, so that `fossil sync` [is functionally equivalent
107to](./sync.wiki#sync):
108
109        fossil push ; fossil pull
110
111There is no implicit “and update the local working directory” step in Fossil’s
112push, pull, or sync commands, as there is with `git pull`.
113
114Someone coming from the Git perspective may perceive that `fossil up`
115has two purposes:
116
117*   Without the optional `VERSION` argument, it updates the working
118    checkout to the tip of the current branch, as `git pull` does.
119
120*   Given a `VERSION` argument, it updates to the named version. If that’s the
121    name of a branch, it updates to the *tip* of that branch, as
122    `git checkout BRANCH` does.
123
124In fact, these are the same operation, so they’re the same command in
125Fossil. The first form simply allows the `VERSION` to be implicit: the
126tip of the current branch.
127
128We think this is a more sensible command design than `git pull` vs
129`git checkout`. ([…vs `git checkout` vs `git checkout`!][gcokoan])
130
131[fpull]:   /help?cmd=pull
132[gpull]:   https://git-scm.com/docs/git-pull
133[gcokoan]: https://stevelosh.com/blog/2013/04/git-koans/#s2-one-thing-well
134
135
136#### <a id="rname"></a> Naming Repositories
137
138The Fossil repository database file can be named anything
139you want, with a single exception: if you’re going to use the
140[`fossil server DIRECTORY`][server] feature, the repositories you wish
141to serve need to be stored together in a flat directory and have
142"`.fossil`" suffixes. That aside, you can follow any other convention that
143makes sense to you.
144
145This author uses a scheme like the following on mobile machines that
146shuttle between home and the office:
147
148``` pikchr toggle indent
149scale=0.8
150box "~/museum/" fit
151move right 0.1
152line right dotted
153move right 0.05
154box invis "where one stores valuable fossils" ljust
155
156arrow down 50% from first box.s then right 50%
157box "work/" fit
158move right 0.1
159line dotted
160move right 0.05
161box invis "projects from $dayjob" ljust
162
163arrow down 50% from 2nd vertex of previous arrow then right 50%
164box "home/" fit
165move right 0.1
166line dotted right until even with previous line.end
167move right 0.05
168box invis "personal at-home projects" ljust
169
170arrow down 50% from 2nd vertex of previous arrow then right 50%
171box "other/" fit
172move right 0.1
173line dotted right until even with previous line.end
174move right 0.05
175box invis "clones of Fossil itself, SQLite, etc." ljust
176```
177
178On a Windows box, you might instead choose "`C:\Fossils`"
179and do without the subdirectory scheme, for example.
180
181
182#### <a id="close" name="dotfile"></a> Closing a Check-Out
183
184The [`fossil close`][close] command dissociates a check-out directory from the
185Fossil repository database, nondestructively inverting [`fossil open`][open].
186(Contrast [its closest inverse](#worktree), `git worktree remove`, which *is*
187destructive in Git!) This Fossil command does not
188remove the managed files, and unless you give the `--force`
189option, it won’t let you close the check-out with uncommitted changes to
190those managed files.
191
192The `close` command also refuses to run without `--force` when you have
193certain other precious per-checkout data that Fossil stores in the
194`.fslckout` file at the root of a check-out directory. This is a SQLite
195database that keeps track of local state such as what version you have
196checked out, the contents of the [stash] for that working directory, the
197[undo] buffers, per-checkout [settings][set], and so forth. The stash
198and undo buffers are considered precious uncommitted changes,
199so you have to force Fossil to discard these as part of closing the
200check-out.
201
202Thus, `.fslckout` is not the same thing as `.git`!
203
204In native Windows builds of Fossil — that is, excluding Cygwin and WSL
205builds, which follow POSIX conventions —  this file is called `_FOSSIL_`
206instead to get around the historical 3-character extension limit with
207certain legacy filesystems.
208
209Closing a check-out directory is a rare operation. One use case
210is that you’re about to delete the directory, so you want Fossil to forget about it
211for the purposes of commands like [`fossil all`][all]. Even that isn’t
212necessary, because Fossil will detect that this has happened and forget
213the working directory for you.
214
215[all]: /help?cmd=all
216
217
218#### <a id="worktree"></a> Git Worktrees
219
220There are at least three different ways to get [Fossil-style multiple
221check-out directories][mcw] with Git.
222
223The old way is to simply symlink the `.git` directory between working
224trees:
225
226        mkdir ../foo-branch
227        ln -s ../actual-clone-dir/.git .
228        git checkout foo-branch
229
230The symlink trick has a number of problems, the largest being that
231symlinks weren’t available on Windows until Vista, and until the Windows
23210 Creators Update was released in spring of 2017, you had to be an
233Administrator to use the feature besides. ([Source][wsyml]) Git solved
234this problem back when Windows XP was Microsoft’s current offering
235with the `git-worktree` command, added in Git 2.5:
236
237        git worktree add ../foo-branch foo-branch
238        cd ../foo-branch
239
240That is approximately equivalent to this in Fossil:
241
242        mkdir ../foo-branch
243        cd ../foo-branch
244        fossil open /path/to/repo.fossil foo-branch
245
246The Fossil alternative is wordier, but this tends to be one-time setup,
247not something you do everyday. This author keeps a “scratch” checkout
248for cases where is isn’t appropriate to reuse the “trunk” checkout. The
249other peer checkouts therefore tend to track long-lived branches, so
250they rarely change once a development machine is set up.
251
252That then leads us to the closest equivalent in Git to [closing a Fossil
253check-out](#close):
254
255        git worktree remove .
256
257Note, however, that unlike `fossil close`, once the Git command
258determines that there are no uncommitted changes, it blows away all of
259the checked-out files! Fossil’s alternative is shorter, easier to
260remember, and safer.
261
262There’s another way to get Fossil-like separate worktrees in Git:
263
264        git clone --separate-git-dir repo.git https://example.com/repo
265
266This allows you to have your Git repository directory entirely separate
267from your working tree, with `.git` in the check-out directory being a
268file that points to `../repo.git`, in this example.
269
270As of Fossil 2.14, there is a direct equivalent:
271
272        fossil clone https://example.com/repo
273
274It’s a shorter command because we deduce `repo.fossil` and the `repo/`
275working directory from the last element of the path in the URI. If you
276wanted to override both deductions, you’d say:
277
278        fossil clone --workdir foo https://example.com/repo/bar
279
280That gets you `bar.fossil` with a `foo/` working directory alongside it.
281
282[mcw]:   ./ckout-workflows.md#mcw
283[wsyml]: https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/
284
285
286#### <a id="iip"></a> Init In Place
287
288To illustrate the differences that Fossil’s separation of repository
289from working directory creates in practice, consider this common Git “init in place”
290method for creating a new repository from an existing tree of files,
291perhaps because you are placing that project under version control for
292the first time:
293
294        cd long-established-project
295        git init
296        git add *
297        git commit -m "Initial commit of project."
298
299The closest equivalent in Fossil is:
300
301        cd long-established-project
302        fossil init .fsl
303        fossil open --force .fsl
304        fossil add *
305        fossil ci -m "Initial commit of project."
306
307Note that unlike in Git, you can abbreviate the “`commit`” command in
308Fossil as “`ci`” for compatibility with CVS, Subversion, etc.
309
310This creates a `.fsl` repo DB at the root of the project check-out to
311emulate the `.git` repo dir. We have to use the `--force` flag on
312opening the new repo because Fossil expects you to open a repo into an
313empty directory in order to avoid spamming the contents of a repo over
314an existing directory full of files. Here, we know the directory
315contains files that will soon belong in the repository, though, so we
316override this check. From then on, Fossil works like Git, for the
317purposes of this example.
318
319We’ve drawn this example to create a tight parallel between Fossil and
320Git, not to commend this `.fsl`-at-project-root trick to you. A better
321choice would be `~/museum/home/long-established-project.fossil`, if
322you’re following [the directory scheme exemplified above](#rname). That said, it
323does emphasize an earlier point: Fossil doesn’t care where you put the
324repo DB file or what you name it.
325
326
327[clone]:  /help?cmd=clone
328[close]:  /help?cmd=close
329[gloss]:  ./whyusefossil.wiki#definitions
330[open]:   /help?cmd=open
331[set]:    /help?cmd=setting
332[server]: /help?cmd=server
333[stash]:  /help?cmd=stash
334[undo]:   /help?cmd=undo
335
336
337## <a id="log"></a> Fossil’s Timeline Is The “Log”
338
339Git users often need to use the `git log` command to dig linearly through
340commit histories due to its [weak data model][wdm], giving [O(n)
341performance][ocomp].
342
343Fossil parses a huge amount of information out of commits that allow it
344to produce its [timeline CLI][tlc] and [its `/timeline` web view][tlw]
345using indexed SQL lookups, which generally have the info you would have
346to manually extract from `git log`, produced much more quickly than Git
347can, all else being equal: operations over [SQLite’s B-tree data structures][btree]
348generally run in O(log n) time, faster than O(n) for equal *n* when the
349constants are equal. Yet the constants are *not* equal because Fossil
350reads from a single disk file rather than visit potentially many
351files in sequence as Git must, so the OS’s buffer cache can result in
352[still better performance][35pct].
353
354Unlike Git’s log, Fossil’s timeline shows info across branches by
355default, a feature for maintaining better situational awareness. Although the
356`fossil timeline` command has no way to show a single branch’s commits,
357you can restrict your view like this using the web UI equivalent by
358clicking the name of a branch on the `/timeline` or `/brlist` page. (Or
359manually, by adding the `r=` query parameter.) Note that even in this
360case, the Fossil timeline still shows other branches where they interact
361with the one you’ve referenced in this way; again, better situational
362awareness.
363
364
365#### <a id="emu-log"></a> Emulating `git log`
366
367If you truly need a backwards-in-time-only view of history in Fossil to
368emulate `git log`, this is as close as you can currently come:
369
370        fossil timeline parents current
371
372Again, though, this isn’t restricted to a single branch, as `git log`
373is.
374
375Another useful rough equivalent is:
376
377        git log --raw
378        fossil time -v
379
380This shows what changed in each version, though Fossil’s view is more a
381summary than a list of raw changes. To dig deeper into single commits,
382you can use Fossil’s [`info` command][infoc] or its [`/info` view][infow].
383
384Inversely, you may more exactly emulate the default `fossil timeline`
385output with `git log --name-status`.
386
387
388#### <a id="whatchanged"></a> What Changed?
389
390A related — though deprecated — command is `git whatchanged`, which gives results similar to
391`git log --raw`, so we cover it here.
392
393Though there is no `fossil whatchanged` command, the same sort of
394information is available. For example, to pull the current changes from
395the remote repository and then inspect them before updating the local
396working directory, you might say this in Git:
397
398        git fetch
399        git whatchanged ..@{u}
400
401…which you can approximate in Fossil as:
402
403        fossil pull
404        fossil up -n
405        fossil diff --from tip
406
407To invert the `diff` to show a more natural patch, the command needs to
408be a bit more complicated, since you can’t currently give `--to`
409without `--from`.
410
411        fossil diff --from current --to tip
412
413Rather than use the “dry run” form of [the `update` command][up], you can
414say:
415
416        fossil timeline after current
417
418…or if you want to restrict the output to the current branch:
419
420        fossil timeline descendants current
421
422
423#### <a id="ckin-names"></a> Symbolic Check-In Names
424
425Note the use of [human-readable symbolic version names][scin] in Fossil
426rather than [Git’s cryptic notations][gcn].
427
428For a more dramatic example of this, let us ask Git, “What changed since the
429beginning of last month?” being October 2020 as I write this:
430
431        git log master@{2020-10-01}..HEAD
432
433That’s rather obscure! Fossil answers the same question with a simpler
434command:
435
436        fossil timeline after 2020-10-01
437
438You may need to add `-n 0` to bypass the default output limit of
439`fossil timeline`, 20 entries. Without that, this command reads
440almost like English.
441
442Some Git users like to write commands like the above so:
443
444        git log @{2020-10-01}..@
445
446Is that better? “@” now means two different things: an at-time reference
447and a shortcut for `HEAD`!
448
449If you are one of those that like short commands, Fossil’s method is
450less cryptic: it lets you shorten words in most cases up to the point
451that they become ambiguous. For example, you may abbreviate the last
452`fossil` command in the prior section:
453
454        fossil tim d c
455
456…beyond which the `timeline` command becomes ambiguous with `ticket`.
457
458Some Fossil users employ shell aliases, symlinks, or scripts to shorten
459the command still further:
460
461        alias f=fossil
462        f tim d c
463
464Granted, that’s rather obscure, but you you can also choose something
465intermediate like “`f time desc curr`”, which is reasonably clear.
466
467[35pct]: https://www.sqlite.org/fasterthanfs.html
468[btree]: https://sqlite.org/btreemodule.html
469[gcn]:   https://git-scm.com/docs/gitrevisions
470[infoc]: /help?cmd=info
471[infow]: /help?cmd=/info
472[ocomp]: https://www.bigocheatsheet.com/
473[tlc]:   /help?cmd=timeline
474[tlw]:   /help?cmd=/timeline
475[up]:    /help?cmd=update
476[wdm]:   ./fossil-v-git.wiki#durable
477
478
479## <a id="dhead"></a> Detached HEAD State
480
481The SQL indexes in Fossil which we brought up above have a very useful
482side benefit: you cannot have a [detached HEAD state][gdh] in Fossil,
483the source of untold pain and data loss in Git. It simply cannot be done
484in Fossil, because the indexes always let us find our way back into the
485hash tree.
486
487
488## <a id="slcom"></a> Summary Line Convention In Commit Comments
489
490The Git convention of a [length-limited summary line][lsl] at the start
491of commit comments has no equivalent in Fossil. You’re welcome to style
492your commit comments thus, but the convention isn’t used or enforced
493anywhere in Fossil. For instance, setting `EDITOR=vim` and making a
494commit doesn’t do syntax highlighting on the commit message to warn that
495you’ve gone over the conventional limit on the first line, and the
496Fossil web timeline display doesn’t show the summary line in bold.
497
498If you wish to follow such conventions in a Fossil project, you may want
499to enable the “Allow block-markup in timeline” setting under Admin →
500Timeline in the web UI to prevent Fossil from showing the message as a
501single paragraph, sans line breaks. [Skin customization][cskin] would
502allow you to style the first line of the commit message in bold in
503`/timeline` views.
504
505[cskin]: ./customskin.md
506[lsl]:   https://chris.beams.io/posts/git-commit/#limit-50
507
508
509
510<a id="staging"></a>
511## There Is No Staging Area
512
513Fossil omits the "Git index" or "staging area" concept.  When you
514type "`fossil commit`" _all_ changes in your check-out are committed,
515automatically.  There is no need for the "-a" option as with Git.
516
517If you only want to commit _some_ of the changes, list the names
518of the files or directories you want to commit as arguments, like this:
519
520        fossil commit src/feature.c doc/feature.md examples/feature
521
522Note that the last element is a directory name, meaning “any changed
523file under the `examples/feature` directory.”
524
525Although there are currently no
526<a id="csplit"></a>[commit splitting][gcspl] features in Fossil like
527`git add -p`, `git commit -p`, or `git rebase -i`, you can get the same
528effect by converting an uncommitted change set to a patch and then
529running it through [Patchouli].
530
531Rather than use `fossil diff -i` to produce such a patch, a safer and
532more idiomatic method would be:
533
534        fossil stash save -m 'my big ball-o-hackage'
535        fossil stash diff > my-changes.patch
536
537That stores your changes in the stash, then lets you operate on a copy
538of that patch. Each time you re-run the second command, it will take the
539current state of the working directory into account to produce a
540potentially different patch, likely smaller because it leaves out patch
541hunks already applied.
542
543In this way, the combination of working tree and stash replaces the need
544for Git’s index feature.
545
546This also solves a philosophical problem with `git commit -p`: how can
547you test that a split commit doesn’t break anything if you do it as part
548of the commit action? Git’s lack of an autosync feature means you can
549commit locally and then rewrite history if the commit doesn’t work out,
550but we’d rather make changes only to the working directory, test the
551changes there, and only commit once we’re sure it’s right.
552
553This also explains why we don’t have anything like `git rebase -i`
554to split an existing commit: in Fossil, commits are *commitments,* not
555something you want to go back and rewrite later.
556
557If someone does [contribute][ctrb] a commit splitting feature to Fossil,
558we’d expect it to be an interactive form of
559[`fossil stash apply`][stash], rather than follow Git’s ill-considered
560design leads.
561
562[ctrb]:      https://fossil-scm.org/fossil/doc/trunk/www/contribute.wiki
563[gcspl]:     https://git-scm.com/docs/git-rebase#_splitting_commits
564[Patchouli]: https://pypi.org/project/patchouli/
565
566
567<a id="bneed"></a>
568## Create Branches at Point of Need, Rather Than Ahead of Need
569
570Fossil prefers that you create new branches as part of the first commit
571on that branch:
572
573        fossil commit --branch my-branch
574
575If that commit is successful, your local check-out directory is then
576switched to the tip of that branch, so subsequent commits don’t need the
577“`--branch`” option. You simply say `fossil commit` again to continue
578adding commits to the tip of that branch.
579
580To switch back to the parent branch, say something like:
581
582        fossil update trunk
583
584(This is approximately equivalent to `git checkout master`.)
585
586Fossil does also support the Git style, creating the branch ahead of
587need:
588
589        fossil branch new my-branch
590        fossil up my-branch
591        ...work on first commit...
592        fossil commit
593
594This is more verbose, giving the same overall effect though the initial
595actions are inverted: create a new branch for the first commit, switch
596the check-out directory to that branch, and make that first commit. As
597above, subsequent commits are descendants of that initial branch commit.
598We think you’ll agree that creating a branch as part of the initial
599commit is simpler.
600
601Fossil also allows you to move a check-in to a different branch
602*after* you commit it, using the "`fossil amend`" command.
603For example:
604
605        fossil amend current --branch my-branch
606
607This works by inserting a tag into the repository that causes the web UI
608to relabel commits from that point forward with the new name. Like Git,
609Fossil’s fundamental data structure is the interlinked DAG of commit
610hashes; branch names are supplemental data for making it easier for the
611humans to understand this DAG, so this command does not change the core
612history of the project, only annotate it for better display to the
613humans.
614
615(The version string “current” is one of the [special check-in names][scin] in Fossil. See
616that document for the many other names you can give to “`amend`”, or
617indeed to any other Fossil command documented to accept a `VERSION` or
618`NAME` string.)
619
620[scin]: ./checkin_names.wiki
621
622
623<a id="autosync"></a>
624## Autosync
625
626Fossil’s [autosync][wflow] feature, normally enabled, has no
627equivalent in Git. If you want Fossil to behave like Git, you can turn
628it off:
629
630        fossil set autosync 0
631
632However, it’s better to understand what the feature does and why it is enabled by
633default.
634
635When autosync is enabled, Fossil automatically pushes your changes
636to the remote server whenever you "`fossil commit`", and it
637pulls all remote changes down to your local clone of the repository as
638part of a "`fossil update`".
639This provides most of the advantages of a centralized version control
640system while retaining the advantages of distributed version control:
641
6421.  Your work stays synced up with your coworkers’ efforts as long as your
643    machine can connect to the remote repository. At need, you can go
644    off-network and continue work atop the last version you synced with
645    the remote.
646
6472.  It provides immediate off-machine backup of your commits. Unlike
648    centralized version control, though, you can still work while
649    disconnected; your changes will sync up with the remote once you get
650    back online.
651
6523.  Because there is little distinction between the clones in the Fossil
653    model — unlike in Git, where clones often quickly diverge from each
654    other, quite possibly on purpose — the backup advantage applies in inverse
655    as well: if the remote server falls over dead, one of those with a
656    clone of that repository can stand it back up, and everyone can get
657    back to work simply by re-pointing their local repo at the new
658    remote.  If the failed remote comes back later, it can sync with the
659    new central version, then perhaps take over as the primary source of
660    truth once again.
661
662    (There are caveats to this, [covered elsewhere][bu].)
663
664[bu]:    ./backup.md
665[setup]: ./caps/admin-v-setup.md#apsu
666[wflow]: ./concepts.wiki#workflow
667
668
669<a id="syncall"></a>
670## Sync Is All-or-Nothing
671
672Fossil does not support the concept of syncing, pushing, or pulling
673individual branches.  When you sync/push/pull in Fossil, it
674processes all artifacts in its hash tree:
675branches, tags, wiki articles, tickets, forum posts, technotes…
676This is [not quite “everything,” full stop][bu], but it’s close.
677
678Furthermore, branch *names* sync automatically in Fossil, not just the
679content of those branches. That means this common Git command:
680
681        git push origin master
682
683…is simply this in Fossil:
684
685        fossil push
686
687Fossil doesn’t need to be told what to push or where to push it: it just
688keeps using the same remote server URL you gave it last
689until you [tell it to do something different][rem], and it pushes all
690branches, not just one named local branch.
691
692[rem]: /help?cmd=remote
693
694
695<a id="trunk"></a>
696## The Main Branch Is Called "`trunk`"
697
698In Fossil, the default name for the main branch
699is "`trunk`".  The "`trunk`" branch in Fossil corresponds to the
700"`master`" branch in stock Git or to [the “`main`” branch in GitHub][mbgh].
701
702Because the `fossil git export` command has to work with both stock Git
703and with GitHub, Fossil uses Git’s traditional default rather than
704GitHub’s new default: your Fossil repo’s “trunk” branch becomes “master”
705when [mirroring to GitHub][mirgh] unless you give the `--mainbranch`
706option added in Fossil 2.14.
707
708We do not know what happens on subsequent exports if you later rename
709this branch on the GitHub side.
710
711[mbgh]:  https://github.com/github/renaming
712[mirgh]: ./mirrortogithub.md
713
714
715<a id="unmanaged"></a>
716## The "`fossil status`" Command Does Not Show Unmanaged Files
717
718The "`fossil status`" command shows you what files in your check-out have
719been edited and scheduled for adding or removing at the next commit.
720But unlike "`git status`", the "`fossil status`" command does not warn
721you about unmanaged files in your local check-out.  There is a separate
722"`fossil extras`" command for that.
723
724
725<a id="rebase"></a>
726## There Is No Rebase
727
728Fossil does not support rebase, [on purpose][3].
729
730This is a deliberate design decision that the Fossil community has
731thought about carefully and discussed many times, resulting in the
732linked document. If you are fond of rebase, you should read it carefully
733before expressing your views: it not only answers many of the common
734arguments in favor of rebase known at the time the document’s first
735draft was written, it’s been revised multiple times to address less
736common objections as well. Chances are not good that you are going to
737come up with a new objection that we haven’t already considered and
738addressed there.
739
740There is only one sub-feature of `git rebase` that is philosophically
741compatible with Fossil yet which currently has no functional equivalent.
742We [covered this and the workaround for its lack](#csplit) above.
743
744[3]: ./rebaseharm.md
745
746
747## <a id="cdiff"></a> Colorized Diffs
748
749The graphical diffs in the Fossil web UI and `fossil diff --tk` use
750color to distinguish insertions, deletions, and replacements, but unlike
751with `git diff` when the output is to an ANSI X3.64 capable terminal,
752`fossil diff` does not.
753
754There are a few easy ways to add this feature to Fossil, though.
755
756One is to install
757[`colordiff`][cdiff], which is included in [many package systems][cdpkg],
758then say:
759
760        fossil set --global diff-command 'colordiff -wu'
761
762Because this is unconditional, unlike `git diff --color=auto`, you will
763then have to remember to add the `-i` option to `fossil diff` commands
764when you want color disabled, such as when producing `patch(1)` files
765or piping diff output to another
766command that doesn’t understand ANSI escape sequences. There’s an
767example of this [below](#dstat).
768
769Another way, which avoids this problem, is to say instead:
770
771        fossil set --global diff-command 'git diff --no-index'
772
773This delegates `fossil diff` to `git diff` by using the latter’s
774ability to run on files not inside any repository.
775
776[cdpkg]: https://repology.org/project/colordiff/versions
777
778
779## <a id="show"></a> Showing Information About Commits
780
781While there is no direct equivalent to Git’s “`show`” command, similar
782functionality is present in Fossil under other commands:
783
784
785#### <a id="patch"></a> Show a Patch for a Commit
786
787        git show -p COMMIT_ID
788
789…gives much the same output as
790
791        fossil diff --checkin COMMIT_ID
792
793…only without the patch email header. Git comes out of the [LKML] world,
794where emailing a patch is a normal thing to do. Fossil is [designed for
795cohesive teams][devorg] where such drive-by patches are rarer.
796
797You can use any of [Fossil’s special check-in names][scin] in place of
798the `COMMIT_ID` in this and later examples. Fossil docs usually say
799“`VERSION`” or “`NAME`” where this is allowed, since the version string
800or name might not refer to a commit ID, but instead to a forum post, a
801wiki document, etc. For instance, the following command answers the question “What did
802I just commit?”
803
804        fossil diff --checkin tip
805
806…or equivalently using a different symbolic commit name:
807
808        fossil diff --from prev
809
810[devorg]: ./fossil-v-git.wiki#devorg
811[LKML]:   https://lkml.org/
812
813
814#### <a id="cmsg"></a> Show a Specific Commit Message
815
816        git show -s COMMIT_ID
817
818
819…is
820
821        fossil time -n 1 COMMIT_ID
822
823…or with a shorter, more obvious command, though with more verbose output:
824
825        fossil info COMMIT_ID
826
827The `fossil info` command isn’t otherwise a good equivalent to
828`git show`; it just overlaps its functionality in some areas. Much of
829what’s missing is present in the corresponding [`/info` web
830view][infow], though.
831
832
833#### <a id="dstat"></a> Diff Statistics
834
835Fossil’s closest internal equivalent to commands like
836`git show --stat` is:
837
838        fossil diff -i --from 2020-04-01 --numstat
839
840The `--numstat` output is a bit cryptic, so we recommend delegating
841this task to [the widely-available `diffstat` tool][dst], which gives
842a histogram in its default output mode rather than bare integers:
843
844        fossil diff -i -v --from 2020-04-01 | diffstat
845
846We gave the `-i` flag in both cases to force Fossil to use its internal
847diff implementation, bypassing [your local `diff-command` setting][dcset].
848The `--numstat` option has no effect when you have an external diff
849command set, and some diff command alternatives like
850[`colordiff`][cdiff] (covered [above](#cdiff)) produce output that confuses `diffstat`.
851
852If you leave off the `-v` flag in the second example, the `diffstat`
853output won’t include info about any newly-added files.
854
855[cdiff]: https://www.colordiff.org/
856[dcset]: https://fossil-scm.org/home/help?cmd=diff-command
857[dst]:   https://invisible-island.net/diffstat/diffstat.html
858
859
860<a id="btnames"></a>
861## Branch And Tag Names
862
863Fossil has no special restrictions on the names of tags and branches,
864though you might want to keep [Git's tag and branch name restrictions][gcrf]
865in mind if you plan on [mirroring your Fossil repository to GitHub][mirgh].
866
867Fossil does not require tag and branch names to be unique.  It is
868common, for example, to put a "`release`" tag on every release for a
869Fossil-hosted project. This does not create a conflict in Fossil, since
870Fossil resolves the ambiguity in a predictable way: the newest match
871wins. Therefore, “`fossil up release`” always gets you the current
872release in a project that uses this tagging convention.
873
874[The `fossil git export` command][fge] squashes repeated tags down to a
875single instance to avoid confusing Git, exporting only the newest tag,
876emulating Fossil’s own ambiguity resolution rule as best it can within
877Git’s limitations.
878
879[fge]:  /help?cmd=git
880[gcrf]: https://git-scm.com/docs/git-check-ref-format
881
882
883
884
885<a id="cpickrev"></a>
886## Cherry-Picking And Reverting Commits
887
888Git’s separate "`git cherry-pick`" and “`git revert`” commands are
889options to the [`fossil merge` command][merge]: `--cherrypick` and
890`--backout`, respectively.
891
892Unlike in Git, the Fossil file format remembers cherrypicks and backouts
893and can later show them as dashed lines on the graphical timeline.
894
895[merge]: /help?cmd=merge
896
897
898
899<a id="mvrm"></a>
900## File Moves And Renames Are Soft By Default
901
902The "[`fossil mv`][mv]" and "[`fossil rm`][rm]" commands work like they
903do in CVS in that they schedule the changes for the next commit by
904default: they do not actually rename or delete the files in your
905check-out.
906
907If you don’t like that default, you can change it globally:
908
909        fossil setting --global mv-rm-files 1
910
911Now these commands behave like in Git in any Fossil repository where
912this setting hasn’t been overridden locally.
913
914If you want to keep Fossil’s soft `mv/rm` behavior most of the time, you
915can cast it away on a per-command basis:
916
917        fossil mv --hard old-name new-name
918
919[mv]: /help?cmd=mv
920[rm]: /help?cmd=rm
921
922
923----
924
925
926## <a id="cvdate" name="cs1"></a> Case Study 1: Checking Out a Version by Date
927
928Let’s get into something a bit more complicated: a case study showing
929how the concepts lined out above cause Fossil to materially differ in
930day-to-day operation from Git.
931
932Why would you want to check out a version of a project by date?  Perhaps
933your customer gave you a vague bug report referencing only a
934date rather than a version. Or, you may be poking semi-randomly through
935history to find a “good” version to anchor the start point of a
936[`fossil bisect`][fbis] operation.
937
938My search engine’s first result for “git checkout by date” is [this
939highly-upvoted accepted Stack Overflow answer][gcod]. The first command
940it gives is based on Git’s [`rev-parse` feature][grp]:
941
942        git checkout master@{2020-03-17}
943
944There are a number of weaknesses in this command. From least to most
945critical:
946
9471.  It’s a bit cryptic. Leave off the refname or punctuation, and it
948    means something else. You cannot simplify the cryptic incantation in
949    the typical use case.
950
9512.  A date string in Git without a time will be interpreted as
952    “[at the local wall clock time on the given date][gapxd],” so the
953    command means something different from one second to the next! This
954    can be a serious problem if there are multiple commits on that date, because
955    the command will give different results depending on the time of
956    day you run it.
957
9583.  It gives misleading output if there is no close match for the date
959    in the local [reflog]. It starts out empty after a fresh clone, and
960    while it does build up as you use that clone, Git [automatically
961    prunes][gle] the reflog to 90 days of history by default. This means
962    the command above can give different results from one machine to the
963    next, or even from one day to the next on the same clone.
964
965    The command won’t fail outright if the reflog can’t resolve the
966    given date: it simply gives the closest commit it can come up with,
967    even if it’s months or years out from your target! Sometimes it
968    gives a warning about the reflog not going back far enough to give a
969    useful result, and sometimes it doesn’t. If you’re on a fresh clone,
970    you are likely to get the “tip” commit’s revision ID no matter what
971    date value you give.
972
973    Git tries its best, but because it’s working from a purgeable and
974    possibly-stale local cache, you cannot trust its results.
975
976Consequently, we cannot recommend this command at all. It’s unreliable even in the
977best case.
978
979That same Stack Overflow answer therefore goes on to recommend an
980entirely different command:
981
982        git checkout $(git rev-list -n 1 --first-parent --before="2020-03-17" master)
983
984We believe you get such answers to Git help requests in part
985because of its lack of an always-up-to-date [index into its log](#log) and in
986part because of its “small tools loosely joined” design philosophy. This
987sort of command is therefore composed piece by piece:
988
989<center>◆  ◆  ◆</center>
990
991“Oh, I know, I’ll search the rev-list, which outputs commit IDs by
992parsing the log backwards from `HEAD`! Easy!”
993
994        git rev-list --before=2020-03-17
995
996“Blast! Forgot the commit ID!”
997
998        git rev-list --before=2020-03-17 master
999
1000“Double blast! It just spammed my terminal with revision IDs! I need to
1001limit it to the single closest match:
1002
1003        git rev-list -n 1 --before=2020-03-17 master
1004
1005“Okay, it gives me a single revision ID now, but is it what I’m after?
1006Let’s take a look…”
1007
1008        git show $(git rev-list -n 1 --before=2020-03-17 master)
1009
1010“Oops, that’s giving me a merge commit, not what I want.
1011Off to search the web… Okay, it says I need to give either the
1012`--first-parent` or `--no-merges` flag to show only regular commits,
1013not merge-commits. Let’s try the first one:”
1014
1015        git show $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
1016
1017“Better. Let’s check it out:”
1018
1019        git checkout $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
1020
1021“Success, I guess?”
1022
1023<center>◆  ◆  ◆</center>
1024
1025This vignette is meant to explain some of Git’s popularity: it rewards
1026the sort of people who enjoy puzzles, many of whom are software
1027developers and thus need a tool like Git. Too bad if you’re just a
1028normal user.
1029
1030And too bad if you’re a Windows user who doesn’t want to use [Git
1031Bash][gbash], since neither of the stock OS command shells have a
1032command interpolation feature needed to run that horrid command.
1033
1034This alternative command still has weakness #2 above: if you run the
1035second `git show` command above on [Git’s own repository][gitgh], your
1036results may vary because there were four non-merge commits to Git on the
103717th of March, 2020.
1038
1039You may be asking with an exasperated huff, “What is your *point*, man?”
1040The point is that the equivalent in Fossil is simply:
1041
1042        fossil up 2020-03-17
1043
1044…which will *always* give the commit closest to midnight UTC on the 17th
1045of March, 2020, no matter whether you do it on a fresh clone or a stale
1046one.  The answer won’t shift about from one clone to the next or from
1047one local time of day to the next. We owe this reliability and stability
1048to three Fossil design choices:
1049
1050*  Parse timestamps from all commits on clone into a local commit index,
1051   then maintain that index through subsequent commits and syncs.
1052
1053*  Use an indexed SQL `ORDER BY` query to match timestamps to commit
1054   IDs for a fast and consistent result.
1055
1056*  Round incomplete timestamp strings up using [rules][frud] consistent across
1057   computers and local time of day.
1058
1059[frud]:   https://fossil-scm.org/home/file/src/name.c?ci=d2a59b03727bc3&ln=122-141
1060[gbash]:  https://appuals.com/what-is-git-bash/
1061[gapxd]:  https://github.com/git/git/blob/7f7ebe054a/date.c#L1298-L1300
1062[gcod]:   https://stackoverflow.com/a/6990682/142454
1063[gdh]:    https://www.git-tower.com/learn/git/faq/detached-head-when-checkout-commit/
1064[gitgh]:  https://github.com/git/git/
1065[gle]:    https://git-scm.com/docs/git-reflog#_options_for_expire
1066[gmc]:    https://github.com/git/git/commit/67b0a24910fbb23c8f5e7a2c61c339818bc68296
1067[grp]:    https://git-scm.com/docs/git-rev-parse
1068[reflog]: https://git-scm.com/docs/git-reflog
1069
1070----
1071
1072## <a id="morigin" name="cs2"></a> Case Study 2: Multiple "origin" Servers
1073
1074Now let us consider a common use case at the time of this writing — during the
1075COVID-19 pandemic — where you’re working from home a lot, going into the
1076office one part-day a week only to do things that have to be done
1077on-site at the office.  Let us also say you have no remote
1078access back into the work LAN, such as because your site IT is paranoid
1079about security. You may still want off-machine backups of your commits
1080while working from home,
1081so you need the ability to quickly switch between the “home” and
1082“work” remote repositories, with your laptop acting as a kind of
1083[sneakernet][sn] link between the big development server at the office
1084and your family’s home NAS.
1085
1086#### Git Method
1087
1088We first need to clone the work repo down to our laptop, so we can work on it
1089at home:
1090
1091        git clone https://dev-server.example.com/repo
1092        cd repo
1093        git remote rename origin work
1094
1095The last command is optional, strictly speaking. We could continue to
1096use Git’s default name for the work repo’s origin — sensibly enough
1097called “`origin`” — but it makes later commands harder to understand, so
1098we rename it here. This will also make the parallel with Fossil easier
1099to draw.
1100
1101The first time we go home after this, we have to reverse-clone the work
1102repo up to the NAS:
1103
1104        ssh my-nas.local 'git init --bare /SHARES/dayjob/repo.git'
1105        git push --all ssh://my-nas.local//SHARES/dayjob/repo.git
1106
1107Realize that this is carefully optimized down to these two long
1108commands. In practice, we’d expect a user typing these commands by hand from memory
1109to need to give four or more commands here instead.
1110Packing the “`git init`” call into the “`ssh`” call is something more
1111often done in scripts and documentation examples than done interactively,
1112which then necessitates a third command before the push, “`exit`”.
1113There’s also a good chance that you’ll forget the need for the `--bare`
1114option here to avoid a fatal complaint from Git that the laptop can’t
1115push into a non-empty repo. If you fall into this trap, among the many
1116that Git lays for newbies, you have to nuke the incorrectly initted
1117repo, search the web or Git man pages to find out about `--bare`, and try again.
1118
1119Having navigated that little minefield,
1120we can tell Git that there is a second origin, a “home” repo in
1121addition to the named “work” repo we set up earlier:
1122
1123        git remote add home ssh://my-nas.local//SHARES/dayjob/repo.git
1124        git config master.remote home
1125
1126We don’t have to push or pull because the remote repo is a complete
1127clone of the repo on the laptop at this point, so we can just get to
1128work now, committing along the way to get our work safely off-machine
1129and onto our home NAS, like so:
1130
1131        git add
1132        git commit
1133        git push
1134
1135We didn’t need to give a remote name on the push because we told it the
1136new upstream is the home NAS earlier.
1137
1138Now Friday comes along, and one of your office-mates needs a feature
1139you’re working on. You agree to come into the office later that
1140afternoon to sync up via the dev server:
1141
1142        git push work master      # send your changes from home up
1143        git pull work master      # get your coworkers’ changes
1144
1145Alternately, we could add “`--set-upstream/-u work`” to the first
1146command if we were coming into work long enough to do several Git-based things, not just pop in and sync.
1147That would allow the second to be just “`git pull`”, but the cost is
1148that when returning home, you’d have to manually reset the upstream
1149again.
1150
1151This example also shows a consequence of that fact that
1152[Git doesn’t sync branch names](#syncall): you have to keep repeating
1153yourself like an obsequious supplicant: “Master, master.” Didn’t we
1154invent computers to serve humans, rather than the other way around?
1155
1156
1157#### Fossil Method
1158
1159Now we’re going to do the same thing using Fossil, with
1160the commands arranged in blocks corresponding to those above for comparison.
1161
1162We start the same way, cloning the work repo down to the laptop:
1163
1164        fossil clone https://dev-server.example.com/repo
1165        cd repo
1166        fossil remote add work https://dev-server.example.com/repo
1167
1168We’ve chosen the new “`fossil clone URI`” syntax added in Fossil 2.14 rather than separate
1169`clone` and `open` commands to make the parallel with Git clearer. [See
1170above](#mwd) for more on that topic.
1171
1172Our [`remote` command][rem] is longer than the Git equivalent because
1173Fossil currently has no short command
1174to rename an existing remote. Worse, unlike with Git, we can’t just keep
1175using the default remote name because Fossil uses that slot in its
1176configuration database to store the *current* remote name, so on
1177switching from work to home, the home URL will overwrite the work URL if
1178we don’t give it an explicit name first.
1179
1180Although the Fossil commands are longer, so far, keep it in perspective:
1181they’re one-time setup costs,
1182easily amortized to insignificance by the shorter day-to-day commands
1183below.
1184
1185On first beginning to work from home, we reverse-clone the Fossil repo
1186up to the NAS:
1187
1188        rsync repo.fossil my-nas.local:/SHARES/dayjob/
1189
1190Now we’re beginning to see the advantage of Fossil’s simpler model,
1191relative to the tricky “`git init && git push`” sequence above.
1192Fossil’s alternative is almost impossible to get
1193wrong: copy this to that.  *Done.*
1194
1195We’re relying on the `rsync` feature that creates up to one level of
1196missing directory (here, `dayjob/`) on the remote. If you know in
1197advance that the remote directory already exists, you could use a
1198slightly shorter `scp` command instead. Even with the extra 2 characters
1199in the `rsync` form, it’s much shorter because a Fossil repository is a
1200single SQLite database file, not a tree containing a pile of assorted
1201files.  Because of this, it works reliably without any of [the caveats
1202inherent in using `rsync` to clone a Git repo][grsync].
1203
1204Now we set up the second remote, which is again simpler in the Fossil
1205case:
1206
1207        fossil remote add home ssh://my-nas.local//SHARES/dayjob/repo.fossil
1208        fossil remote home
1209
1210The first command is nearly identical to the Git version, but the second
1211is considerably simpler. And to be fair, you won’t find the
1212“`git config`” command above in all Git tutorials. The more common
1213alternative we found with web searches is even longer:
1214“`git push --set-upstream home master`”.
1215
1216Where Fossil really wins is in the next step, making the initial commit
1217from home:
1218
1219        fossil ci
1220
1221It’s one short command for Fossil instead of three for Git — or two if
1222you abbreviate it as “`git commit -a && git push`” — because of Fossil’s
1223[autosync feature](#autosync) feature and deliberate omission of a
1224[staging feature](#staging).
1225
1226The “Friday afternoon sync-up” case is simpler, too:
1227
1228        fossil remote work
1229        fossil sync
1230
1231Back at home, it’s simpler still: we may be able to do away with the second command,
1232saying just “`fossil remote home`” because the sync will happen as part
1233of the next commit, thanks once again to Fossil’s autosync feature. If
1234the working branch now has commits from other developers after syncing
1235with the central repository, though, you’ll want to say “`fossil up`” to
1236avoid creating an inadvertent fork in the branch.
1237
1238(Which is easy to fix if it occurs: `fossil merge` without arguments
1239means “merge open tips on the current branch.”)
1240
1241[grsync]: https://stackoverflow.com/q/1398018/142454
1242[qs]:     ./quickstart.wiki
1243[shwmd]:  ./fossil-v-git.wiki#checkouts
1244[sn]:     https://en.wikipedia.org/wiki/Sneakernet
1245